#include "UsrAI.h"
#include <set>
#include <iostream>
#include <unordered_map>
#include <algorithm>      // + sort / max
#include <vector>
#include <unordered_set>
#include <utility>        // + pair
#include <cmath>          // + sqrt
#include <queue>
using namespace std;

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

static constexpr int FARMER_SORT_WOOD_BOAT = 1; // 运输船 (FarmerSort值)
tagGame tagUsrGame;
ins UsrIns;

// --------------- 工具函数，放在 UsrAI.cpp 顶部 -----------------
static inline int pendingCnt(int type){
    auto it = g_ai_state.pending_buildings.find(type);
    return (it == g_ai_state.pending_buildings.end()) ? 0 : it->second;
}

// ---------- 资源 & 指令辅助 ---------- //
// 获取建筑的木材成本
static int getBuildingWoodCost(int type){
    switch(type){
        case BUILDING_HOME:     return BUILD_HOUSE_WOOD;
        case BUILDING_STOCK:    return BUILD_STOCK_WOOD;
        case BUILDING_ARMYCAMP: return BUILD_ARMYCAMP_WOOD;
        case BUILDING_DOCK:     return BUILD_DOCK_WOOD;
        default:                return 0;
    }
}

// 尝试下达建造指令，并记录以供追踪
static bool tryOrderBuilding(AI* ai,int builderSN,int type,int x,int y){
    int id = ai->HumanBuild(builderSN,type,x,y);
    if(id<=0) return false;                               // 指令下达失败
    g_ai_state.build_cmd_to_type[id] = type;              // 记录指令 ID -> 建筑类型
    g_ai_state.pending_buildings[type]++;                 // << 修改：待建建筑计数+1
    g_ai_state.reserved_wood += getBuildingWoodCost(type); // 预留木材
    return true;
}

// 处理上一帧指令的返回结果：若失败则释放预算、允许重试
static void processCommandResults(const tagInfo& info){
    // 遍历所有已发出的、正在追踪的建造指令
    for(auto it = g_ai_state.build_cmd_to_type.begin(); it!=g_ai_state.build_cmd_to_type.end();){
        auto retIter = info.ins_ret.find(it->first); // 查找该指令的返回结果
        // 如果找到了返回结果，并且结果是失败的 (小于0)
        if(retIter!=info.ins_ret.end() && retIter->second < 0){
            int tp = it->second; // 获取建筑类型
            // << 修改：对应建筑类型的待建计数-1
            if(g_ai_state.pending_buildings.count(tp)){
                g_ai_state.pending_buildings[tp]--;
                if(g_ai_state.pending_buildings[tp] <= 0){
                    g_ai_state.pending_buildings.erase(tp);
                }
            }
            g_ai_state.reserved_wood -= getBuildingWoodCost(tp); // 返还预留的木材
            it = g_ai_state.build_cmd_to_type.erase(it); // 从追踪列表中移除该指令
        }else {
            ++it; // 否则，继续检查下一个指令
        }
    }
}


// 全局AI状态变量，用于存储我方AI的内部数据和决策状态
MyAIState g_ai_state;

// ####################################################################
// ##
// ##  核心入口函数
// ##
// ####################################################################

void UsrAI::processData()
{
    // 1. 获取当前帧的全部游戏信息
    tagInfo info = getInfo();

    map<int, tagResource> resource_map;

    for (const auto &res : info.resources)
    {
        resource_map[res.SN] = res;
    }

    // 2. 更新自己的AI状态和数据结构
    updateGameState(info, resource_map);
    processCommandResults(info); // <<<<< 新增：处理上一帧的指令结果

    // 3. 如果区域未初始化，则进行规划
    if (!g_ai_state.zones_initialized)
    {
        const tagBuilding *tc = getTownCenter(info);
        if (tc)
        { // 确保市镇中心存在
            // 调用辅助函数时传入 this 指针
            initializeZones(this, *tc);
            g_ai_state.zones_initialized = true;
        }
    }

    // 4. 根据当前战略阶段，执行相应的决策逻辑
   switch (g_ai_state.stage)
   {
   case 0:
       // 调用辅助函数时传入 this 指针
       executeStage0_EconomicBoom(this, info);
       break;
   case 1:
       // 调用辅助函数时传入 this 指针
       executeStage1_Upgrading(this, info); // New stage for upgrading
       break;
   case 2:
       // 调用辅助函数时传入 this 指针
       executeStage2_ToolAgeEconomyAndNavy(this, info); // Original Stage 1, now Stage 2
       break;
   default:
       break;
   }
   return;
}

// 1. 状态更新与管理 (State Update & Management)
// 此函数只更新数据，不执行动作，所以不需要 AI 指针
void updateGameState(const tagInfo &info, const map<int, tagResource> &resource_map)
{
    // 首次初始化己方陆地标记 - 将开局可见的所有陆地标记为己方领土
    if (!g_ai_state.ownLand_initialized) {
        const tagBuilding* tc = getTownCenter(info);
        if (tc) {
            int tc_x = tc->BlockDR;
            int tc_y = tc->BlockUR;
            
            // 从市镇中心开始洪泛填充，标记所有连通的陆地为己方领土
            queue<Point> q;
            q.push({tc_x, tc_y});
            g_ai_state.ownLand[tc_x][tc_y] = true;
            
            const int dx[4] = {1, -1, 0, 0};
            const int dy[4] = {0, 0, 1, -1};
            
            while (!q.empty()) {
                Point p = q.front();
                q.pop();
                
                for (int k = 0; k < 4; k++) {
                    int nx = p.x + dx[k];
                    int ny = p.y + dy[k];
                    
                    if (nx >= 0 && nx < 128 && ny >= 0 && ny < 128 && !g_ai_state.ownLand[nx][ny]) {
                        const auto &tile = (*info.theMap)[nx][ny];
                        if (tile.type == MAPPATTERN_GRASS || tile.type == MAPPATTERN_DESERT) {
                            g_ai_state.ownLand[nx][ny] = true;
                            q.push({nx, ny});
                        }
                    }
                }
            }
        }
        g_ai_state.ownLand_initialized = true;
        // 不添加调试信息，避免刷屏
    }
    
    // 清空上一帧的数据，为当前帧信息做准备
    g_ai_state.farmers.clear();
    g_ai_state.buildings.clear();
    g_ai_state.idleFarmerSNs.clear();
    g_ai_state.woodcutterSNs.clear();
    g_ai_state.stoneMinerSNs.clear();
    g_ai_state.hunterSNs.clear();
    g_ai_state.fisherSNs.clear();
    g_ai_state.fishing_boat_count = 0;
    g_ai_state.completed_dock_count = 0;

    // 初始化一个128x128的网格，用于建筑放置检测
    // 1表示被占用或不可建造，0表示空闲
    for (int i = 0; i < 128; ++i)
    {
        for (int j = 0; j < 128; ++j)
        {
            g_ai_state.grid[i][j] = 0; // 可建造的草地
            if ((*info.theMap)[i][j].type == MAPPATTERN_UNKNOWN)
            {
                g_ai_state.grid[i][j] = 1; // 未探索为障碍
            }
            if ((*info.theMap)[i][j].type == MAPPATTERN_GRASS && (*info.theMap)[i][j].height == -1)
                g_ai_state.grid[i][j] = 1;
        }
    }
    // 将资源（树、石头等）所在位置标记为已占用
    for (const auto &resource : info.resources)
    {
        switch (resource.Type)
        {
        case RESOURCE_TREE:
        case RESOURCE_STONE:
        case RESOURCE_GOLD:
        case RESOURCE_FISH: // 鱼群/渔场也是物理障碍
        case RESOURCE_GAZELLE:          // 新增：把会乱跑的动物也视作障碍
        case RESOURCE_ELEPHANT:
        case RESOURCE_LION:
            // 资源贴图通常为 2×2，因此将覆盖范围全部标为障碍
            for(int dx=0; dx<2; ++dx){
                for(int dy=0; dy<2; ++dy){
                    int rx = resource.BlockDR + dx;
                    int ry = resource.BlockUR + dy;
                    if(rx>=0 && rx<128 && ry>=0 && ry<128){
                        g_ai_state.grid[rx][ry] = 1;
                    }
                }
            }
            break;
        default:
            // 其他资源类型（如动物尸体）不标记为障碍
            break;
        }
    }
    // 将现有建筑物所占用的地块标记为已占用
    for (const auto &building : info.buildings)
    {
        int sizeX, sizeY;
        getBuildingSize(building.Type, sizeX, sizeY);
        for (int i = 0; i < sizeX; ++i)
        {
            for (int j = 0; j < sizeY; ++j)
            {
                int bx = building.BlockDR + i;
                int by = building.BlockUR + j;
                if (bx >= 0 && bx < 128 && by >= 0 && by < 128)
                {
                    g_ai_state.grid[bx][by] = 1;
                }
            }
        }
        g_ai_state.buildings[building.SN] = building;

        if (building.Type == BUILDING_DOCK && building.Percent == 100)
        {
            g_ai_state.completed_dock_count++; // 船坞已完工，计数器+1
        }
        
        // << 修改：核心逻辑修正 >>
        // 只有当建筑100%完工时，才将其从"待建"清单中移除（计数-1）。
        // 注意：这里的 reserved_wood 也同步修改，以维持预算一致性。
        // 这个改动修正了市场/农场迟迟不造的问题。
        if (building.Percent == 100 && g_ai_state.pending_buildings.count(building.Type) > 0)
        {
            g_ai_state.pending_buildings[building.Type]--;
            g_ai_state.reserved_wood -= getBuildingWoodCost(building.Type);
            if(g_ai_state.pending_buildings[building.Type] == 0)
                g_ai_state.pending_buildings.erase(building.Type);
        }
    }

    // 遍历所有农民，更新他们的信息，并根据当前状态进行分类
    for (const auto &farmer : info.farmers)
    {
        g_ai_state.farmers[farmer.SN] = farmer;
        
        // 标记农民所在位置为已占用
        g_ai_state.grid[farmer.BlockDR][farmer.BlockUR] = 1;

        if (farmer.FarmerSort == 2)
        { // 是渔船
            g_ai_state.fishing_boat_count++;
            continue;
        }

        if (farmer.FarmerSort != 0)
            continue; // 只处理我方农民

        if (farmer.NowState == HUMAN_STATE_IDLE)
        {
            g_ai_state.idleFarmerSNs.push_back(farmer.SN); // 归类为空闲农民
        }
        else if (farmer.NowState == HUMAN_STATE_WORKING)
        {
            auto it = resource_map.find(farmer.WorkObjectSN);
            if (it != resource_map.end())
            {
                const tagResource &res = it->second;
                switch (res.Type)
                {
                case RESOURCE_TREE:
                    g_ai_state.woodcutterSNs.push_back(farmer.SN);
                    break;
                case RESOURCE_STONE:
                    g_ai_state.stoneMinerSNs.push_back(farmer.SN);
                    break;
                case RESOURCE_GAZELLE:
                case RESOURCE_ELEPHANT:
                    g_ai_state.hunterSNs.push_back(farmer.SN);
                    break;
                case RESOURCE_FISH:
                    g_ai_state.fisherSNs.push_back(farmer.SN);
                    break;
                }
            }
        }
    }
    // 增加排序，确保AI行为的确定性
    std::sort(g_ai_state.idleFarmerSNs.begin(), g_ai_state.idleFarmerSNs.end());

    for (const auto& army : info.armies) {
        if (army.BlockDR >= 0 && army.BlockDR < 128 && army.BlockUR >= 0 && army.BlockUR < 128) {
            g_ai_state.grid[army.BlockDR][army.BlockUR] = 1;
        }
    }
}

// 2. 宏观战略阶段 (Strategy Stages)
// 阶段0：石器时代经济发展。核心目标是快速发展经济，采集资源，并准备升级到工具时代
void executeStage0_EconomicBoom(AI *ai, const tagInfo &info)
{
    auto available_idle_farmers = g_ai_state.idleFarmerSNs;
    // 计算"可支配木材"= 实际木材 - 已预留木材
    int temp_wood  = info.Wood - g_ai_state.reserved_wood;
    if(temp_wood < 0) temp_wood = 0; // 确保不会是负数
    int temp_meat = info.Meat;
    int temp_stone = info.Stone;

    const tagBuilding *tc = getTownCenter(info);
    if (!tc)
        return; // 如果没有城镇中心，则无法执行任何操作

    // 1. [高效] 统一信息采集：一次遍历获取所有需要的建筑状态
    bool has_army_camp = false;
    bool has_dock = false;
    int  house_count = 0; // Added: Counter for existing houses

    for (const auto &pair : g_ai_state.buildings)
    {
        const tagBuilding &building = pair.second;
        if (building.Type == BUILDING_ARMYCAMP)
        {
            has_army_camp = true;
        }
        if (building.Type == BUILDING_DOCK)
        {
            has_dock = true;
        }
        if (building.Type == BUILDING_HOME) // Count existing houses
        {
            house_count++;
        }
    }
    
    // ---------- ① 先尝试建"仓库" ----------
    if (!building_type_exists(BUILDING_STOCK) &&
        !available_idle_farmers.empty() &&
        temp_wood >= BUILD_STOCK_WOOD)
    {
        Point pos = {-1,-1};
        static bool granary_debug_shown = false;
        
        // 优先以最近的羚羊为中心螺旋搜索
        // 多候选点评分机制：优先选择距离羚羊最近的合法位置
        vector<Point> candidates;
        vector<int> gazelle_distances;
        const tagBuilding* tc = getTownCenter(info);
        if (tc) {
            if (!granary_debug_shown) {
                ai->DebugText("=== Granary Placement: Multi-candidate scoring ===");
            }
            
            // 收集TC附近所有合法的3x3位置
            for(int r = 1; r <= 30; ++r) {
                for(int i = 0; i < 8 * r; ++i) {
                    Point test = getSpiralPoint(tc->BlockDR, tc->BlockUR, i, r);
                    if(test.x >= 0 && test.x < 128 && test.y >= 0 && test.y < 128 && 
                       isPlacementLegalandSafe(test.x, test.y, 3, 3, info)) {
                        candidates.push_back(test);
                    }
                }
                if(candidates.size() >= 50) break; // 收集足够候选点即可
            }
            
            if (!granary_debug_shown) {
                ai->DebugText("Found " + to_string(candidates.size()) + " candidate positions");
            }
            
            // 为每个候选点计算到最近羚羊的距离
            for(const auto& candidate : candidates) {
                int min_gazelle_dist = 9999;
                for (const auto &resource : info.resources) {
                    if (resource.Type == RESOURCE_GAZELLE) {
                        int dist = abs(candidate.x - resource.BlockDR) + abs(candidate.y - resource.BlockUR);
                        min_gazelle_dist = min(min_gazelle_dist, dist);
                    }
                }
                gazelle_distances.push_back(min_gazelle_dist);
            }
            
            // 选择距离羚羊最近的候选点
            if(!candidates.empty()) {
                int best_idx = 0;
                for(int i = 1; i < candidates.size(); ++i) {
                    if(gazelle_distances[i] < gazelle_distances[best_idx]) {
                        best_idx = i;
                    }
                }
                pos = candidates[best_idx];
                if (!granary_debug_shown) {
                    ai->DebugText("✓ Best granary placement at (" + to_string(pos.x) + "," + to_string(pos.y) + ") with gazelle distance: " + to_string(gazelle_distances[best_idx]));
                }
            }
        }
        
        // 如果羚羊附近找不到位置，尝试海岸位置
        if (pos.x == -1 && (g_ai_state.completed_dock_count > 0 || has_dock)) {
            if (!granary_debug_shown) {
                ai->DebugText("Trying coastal granary placement...");
            }
            pos = findCoastalStockPlacement(ai, info);
        }
        
        // 最后使用默认区域搜索
        if (pos.x == -1) {
            if (!granary_debug_shown) {
                ai->DebugText("Using default military zone for granary...");
            }
            pos = findPlacement(ai, BUILDING_STOCK, available_idle_farmers.back(), info);
        }

        if (pos.x != -1)
        {
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if (tryOrderBuilding(ai, builder, BUILDING_STOCK, pos.x, pos.y))
            {
                temp_wood -= BUILD_STOCK_WOOD;
                ai->DebugText("Building granary at (" + to_string(pos.x) + "," + to_string(pos.y) + ")");
                granary_debug_shown = true; // 只显示一次详细调试信息
            }
        }
    }

    // ---------- ② 船坞（最多 2 个） ----------
    int pending_docks = pendingCnt(BUILDING_DOCK);     // ← 真正条数
    if (g_ai_state.completed_dock_count + pending_docks < 1 &&
        !available_idle_farmers.empty() && temp_wood >= BUILD_DOCK_WOOD)
    {
        Point pos = findDockPlacement(ai, info);
        if(pos.x != -1){
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_DOCK, pos.x, pos.y) ){
                temp_wood -= BUILD_DOCK_WOOD;
                ai->DebugText("Ordering a builder to build a dock.");
            }
        }
    }

    // 2. 核心生产逻辑：持续生产农民
    // 只要资源和人口上限允许，就持续生产农民（上限暂时定为12个）
    if (info.farmers.size() < 12 && tc->Project == 0 && temp_meat >= BUILDING_CENTER_CREATEFARMER_FOOD && info.farmers.size() < info.Human_MaxNum)
    {
        ai->BuildingAction(tc->SN, BUILDING_CENTER_CREATEFARMER);
        temp_meat -= BUILDING_CENTER_CREATEFARMER_FOOD;
        ai->DebugText("Building farmer...");
    }

    // 3. 统一建筑建造逻辑 (使用资源预扣除)

    // 优先级2: 人口快满了，必须造房子 (最多4个)
    if (pendingCnt(BUILDING_HOME) < 1
        && (house_count + pendingCnt(BUILDING_HOME) < 4)
        && !available_idle_farmers.empty() 
        && info.farmers.size() >= info.Human_MaxNum - 1 
        && temp_wood >= BUILD_HOUSE_WOOD) // Added house limit
    {
        Point p = findPlacement(ai, BUILDING_HOME, available_idle_farmers.back(), info);
        if (p.x != -1)
        {
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_HOME, p.x, p.y) ) {
                temp_wood -= BUILD_HOUSE_WOOD;
                ai->DebugText("The population reaches the upper limit, building houses...");
            }
        }
    }
    // --- 额外统计正在造的渔船数量 ---
    int pending_boats = 0;
    for (auto &kv : g_ai_state.buildings)
        if (kv.second.Type == BUILDING_DOCK &&
            kv.second.Project == BUILDING_DOCK_CREATE_SAILING)
            ++pending_boats;

    // --- 人口已用 ---
    int pop_used = static_cast<int>(info.farmers.size() + info.armies.size());
    // 3. 渔船生产逻辑：从所有已完成的船坞生产，直到总数达到4
    if (building_type_exists(BUILDING_STOCK) && g_ai_state.fishing_boat_count < 4 && pop_used < info.Human_MaxNum && temp_wood >= BUILDING_DOCK_CREATE_SAILING_WOOD)
    {
        // 遍历所有我方建筑
        for (const auto &pair : g_ai_state.buildings)
        {
            const tagBuilding &building = pair.second;
            // 如果它是一个已完工且空闲的船坞
            if (building.Type == BUILDING_DOCK && building.Percent == 100 && building.Project == 0)
            {
                ai->BuildingAction(building.SN, BUILDING_DOCK_CREATE_SAILING);
                temp_wood -= BUILDING_DOCK_CREATE_SAILING_WOOD;
                ai->DebugText("A dock is producing a fishing boat...");
                break;
            }
        }
    }



    // 4. [新增] 渔船自动化采集逻辑
    // 这是一个独立的循环，专门处理渔船
    for (const auto &farmer_pair : g_ai_state.farmers)
    {
        const tagFarmer &boat = farmer_pair.second;
        // 如果它是一个渔船(FarmerSort==2) 且 状态为空闲
        if (boat.FarmerSort == 2 && boat.NowState == HUMAN_STATE_IDLE)
        {
            // 持久绑定机制：渔船一旦分配给船坞就固定绑定
            int best_fish_sn = -1;
            
            // 检查该渔船是否已有绑定的船坞
            if (g_ai_state.fishing_boat_dock_assignment.count(boat.SN) == 0) {
                // 首次分配：找到距离这艘船最近的完成船坞并绑定
                int nearest_dock_sn = -1;
                int nearest_dock_dist = 999;
                for (const auto &bd_pair : g_ai_state.buildings) {
                    const tagBuilding &dock = bd_pair.second;
                    if (dock.Type == BUILDING_DOCK && dock.Percent == 100) {
                        int dist = abs(boat.BlockDR - dock.BlockDR) + abs(boat.BlockUR - dock.BlockUR);
                        if (dist < nearest_dock_dist) {
                            nearest_dock_dist = dist;
                            nearest_dock_sn = dock.SN;
                        }
                    }
                }
                if (nearest_dock_sn != -1) {
                    g_ai_state.fishing_boat_dock_assignment[boat.SN] = nearest_dock_sn;
                    ai->DebugText("Fishing boat " + to_string(boat.SN) + " permanently assigned to dock " + to_string(nearest_dock_sn));
                }
            }
            
            // 根据绑定的船坞找最近的渔场
            if (g_ai_state.fishing_boat_dock_assignment.count(boat.SN) > 0) {
                int assigned_dock_sn = g_ai_state.fishing_boat_dock_assignment[boat.SN];
                if (g_ai_state.buildings.count(assigned_dock_sn) > 0) {
                    const tagBuilding &dock = g_ai_state.buildings[assigned_dock_sn];
                    int min_dock_fish_dist = 999;
                    
                    for (const auto &resource : info.resources) {
                        if (resource.Type == RESOURCE_FISH) {
                            int dock_to_fish = abs(dock.BlockDR - resource.BlockDR) + abs(dock.BlockUR - resource.BlockUR);
                            if (dock_to_fish < min_dock_fish_dist) {
                                min_dock_fish_dist = dock_to_fish;
                                best_fish_sn = resource.SN;
                            }
                        }
                    }
                } else {
                    // 绑定的船坞已销毁，重新分配
                    g_ai_state.fishing_boat_dock_assignment.erase(boat.SN);
                }
            }
            
            // 如果没找到合适的，使用原有逻辑（距离渔船最近的渔场）
            if (best_fish_sn == -1) {
                best_fish_sn = findNearestResource({boat.BlockDR, boat.BlockUR}, RESOURCE_FISH, info);
            }
            
            if (best_fish_sn != -1) {
                ai->HumanAction(boat.SN, best_fish_sn);
                ai->DebugText("Fishing boat " + to_string(boat.SN) + " working assigned fishing area " + to_string(best_fish_sn));
            } else {
                // 找不到渔场则进行贴岸探索（节流）
                static std::unordered_map<int,int> lastBoatMoveFrame0;
                int last = lastBoatMoveFrame0.count(boat.SN) ? lastBoatMoveFrame0[boat.SN] : -9999;
                if(info.GameFrame - last > 45){
                    Point tgt = findNextFishingExploreTarget(info);
                    if(tgt.x != -1){
                        ai->HumanMove(boat.SN, tgt.x * BLOCKSIDELENGTH, tgt.y * BLOCKSIDELENGTH);
                        ai->DebugText("Fishing boat " + to_string(boat.SN) + " exploring to (" + to_string(tgt.x) + "," + to_string(tgt.y) + ")");
                        lastBoatMoveFrame0[boat.SN] = info.GameFrame;
                    }
                }
            }
        }
    }

    // 谷仓（1 个，用于时代升级条件和市场前置）
    if (pending_boats + g_ai_state.fishing_boat_count > 2 && !building_type_exists(BUILDING_GRANARY) &&
        !available_idle_farmers.empty() &&
        temp_wood >= BUILD_GRANARY_WOOD &&
        pendingCnt(BUILDING_GRANARY) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_GRANARY, available_idle_farmers.back(), info);
        if(pos.x != -1){
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_GRANARY, pos.x, pos.y) ){
                temp_wood -= BUILD_GRANARY_WOOD;
                ai->DebugText("Building a granary for future upgrades and market.");
            }
        }
    }

    // 兵营（1 个，用于时代升级条件）
    if (g_ai_state.fishing_boat_count == 4 &&
        !has_army_camp &&
        !available_idle_farmers.empty() &&
        temp_wood >= BUILD_ARMYCAMP_WOOD &&
        pendingCnt(BUILDING_ARMYCAMP) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_ARMYCAMP, available_idle_farmers.back(), info);
        if(pos.x != -1){
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_ARMYCAMP, pos.x, pos.y) ){
                temp_wood -= BUILD_ARMYCAMP_WOOD;
                ai->DebugText("Prepare for the Age of Upgrades, building barracks...");
            }
        }
    }


    
    // 优先级0: 检查是否有未完成的建筑需要继续建造
    assignFarmersToUnfinishedBuildings(ai, info, available_idle_farmers);
    
    // 分配剩余的空闲农民去采集资源，按优先级：木材 -> 石头 -> 食物
    for (int farmer_sn : available_idle_farmers)
    {
        // 跳过正在上船的农民，防止被重新分配工作
        if (g_ai_state.boarding_farmers.count(farmer_sn) > 0) {
            continue;
        }

        if (g_ai_state.woodcutterSNs.size() < 7)
        { // 优先保证6个伐木工
            int tree_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_TREE, info);
            if (tree_sn != -1)
            {
                ai->HumanAction(farmer_sn, tree_sn);
            }
        }
        else if (g_ai_state.stoneMinerSNs.size() < 0)
        { // 其次保证0个采石工
            int stone_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_STONE, info);
            if (stone_sn != -1)
            {
                ai->HumanAction(farmer_sn, stone_sn);
            }
        }
        else if (g_ai_state.hunterSNs.size() < 3)
        { // 然后分配4个去打猎
            int animal_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_GAZELLE, info);
            if (animal_sn != -1)
            {
                ai->HumanAction(farmer_sn, animal_sn);
            }
        }
    }
    // 检查是否满足升级到工具时代的条件：500食物和至少两个石器时代特定建筑
    if (info.Meat >= 500 && info.civilizationStage == CIVILIZATION_STONEAGE)
    {
        int required_building_count = 0;
        for (const auto &pair : g_ai_state.buildings)
        {
            if (pair.second.Type == BUILDING_DOCK || pair.second.Type == BUILDING_STOCK ||
                pair.second.Type == BUILDING_ARMYCAMP || pair.second.Type == BUILDING_GRANARY)
            {
                required_building_count++;
            }
        }

        if (required_building_count >= 2)
        {
            ai->BuildingAction(tc->SN, BUILDING_CENTER_UPGRADE); // 升级时代
            ai->DebugText("!!! UPGRADING TO TOOL AGE !!!");
            g_ai_state.stage = 1; // 切换到升级战略阶段
            ai->DebugText("Stage 1: Upgrading to Tool Age. Focusing on resource gathering.");
        }
    }
}

// 新增阶段1：升级中，专注于资源采集，等待时代升级完成
void executeStage1_Upgrading(AI *ai, const tagInfo &info)
{
    // 如果时代已经升级完成，则切换到下一阶段
    if (info.civilizationStage == CIVILIZATION_TOOLAGE)
    {
        g_ai_state.stage = 2; // 切换到工具时代经济和海军阶段
        ai->DebugText("Civilization upgraded to Tool Age. Transitioning to Stage 2.");
        return;
    }

    int temp_wood = info.Wood;

    // 谷仓
    if (!building_type_exists(BUILDING_GRANARY) &&
        !g_ai_state.idleFarmerSNs.empty() &&
        temp_wood >= BUILD_GRANARY_WOOD &&
        pendingCnt(BUILDING_GRANARY) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_GRANARY, g_ai_state.idleFarmerSNs.back(), info);
        if(pos.x != -1){
            int builder = g_ai_state.idleFarmerSNs.back();
            g_ai_state.idleFarmerSNs.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_GRANARY, pos.x, pos.y) ){
                temp_wood -= BUILD_GRANARY_WOOD;
                ai->DebugText("Building a granary for future upgrades and market.");
            }
        }
    }

    // 兵营
    if (!building_type_exists(BUILDING_ARMYCAMP) &&
        !g_ai_state.idleFarmerSNs.empty() &&
        temp_wood >= BUILD_ARMYCAMP_WOOD &&
        pendingCnt(BUILDING_ARMYCAMP) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_ARMYCAMP, g_ai_state.idleFarmerSNs.back(), info);
        if(pos.x != -1){
            int builder = g_ai_state.idleFarmerSNs.back();
            g_ai_state.idleFarmerSNs.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_ARMYCAMP, pos.x, pos.y) ){
                temp_wood -= BUILD_ARMYCAMP_WOOD;
                ai->DebugText("Prepare for the Age of Upgrades, building barracks...");
            }
        }
    }


    // 优先检查未完成的建筑
    auto available_idle_farmers_stage1 = g_ai_state.idleFarmerSNs;
    assignFarmersToUnfinishedBuildings(ai, info, available_idle_farmers_stage1);

    // 在升级过程中，让剩余的空闲农民去砍树
    for (int farmer_sn : available_idle_farmers_stage1)
    {
        // 跳过正在上船的农民，防止被重新分配工作
        if (g_ai_state.boarding_farmers.count(farmer_sn) > 0) {
            continue;
        }

        int tree_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_TREE, info);
        if (tree_sn != -1)
        {
            ai->HumanAction(farmer_sn, tree_sn);
            ai->DebugText("Sent an idle farmer to collect wood during upgrade.");
        }
    }

    // 让所有空闲渔船去渔场捕捞（使用优化的分配逻辑）
    for (const auto &farmer_pair : g_ai_state.farmers)
    {
        const tagFarmer &boat = farmer_pair.second;
        if (boat.FarmerSort == 2 && boat.NowState == HUMAN_STATE_IDLE)
        {
            // 使用优化的渔船分配逻辑
            int best_fish_sn = -1;
            int min_dock_fish_dist = 9999;
            
            // 找到距离这艘船最近的完成船坞
            int nearest_dock_dist = 9999;
            Point nearest_dock_pos = {-1, -1};
            for (const auto &bd_pair : g_ai_state.buildings) {
                const tagBuilding &dock = bd_pair.second;
                if (dock.Type == BUILDING_DOCK && dock.Percent == 100) {
                    int dist = abs(boat.BlockDR - dock.BlockDR) + abs(boat.BlockUR - dock.BlockUR);
                    if (dist < nearest_dock_dist) {
                        nearest_dock_dist = dist;
                        nearest_dock_pos = {dock.BlockDR, dock.BlockUR};
                    }
                }
            }
            
            // 如果找到了船坞，优先选择距离该船坞最近的渔场
            if (nearest_dock_pos.x != -1) {
                for (const auto &resource : info.resources) {
                    if (resource.Type == RESOURCE_FISH) {
                        int dock_fish_dist = abs(nearest_dock_pos.x - resource.BlockDR) + 
                                           abs(nearest_dock_pos.y - resource.BlockUR);
                        if (dock_fish_dist < min_dock_fish_dist) {
                            min_dock_fish_dist = dock_fish_dist;
                            best_fish_sn = resource.SN;
                        }
                    }
                }
            }
            
            // 如果没找到合适的，使用原有逻辑
            if (best_fish_sn == -1) {
                best_fish_sn = findNearestResource({boat.BlockDR, boat.BlockUR}, RESOURCE_FISH, info);
            }
            
            if (best_fish_sn != -1) {
                ai->HumanAction(boat.SN, best_fish_sn);
                ai->DebugText("Sent fishing boat to optimized area during upgrade (dock-distance: " + to_string(min_dock_fish_dist) + ")");
            } else {
                static std::unordered_map<int,int> lastBoatMoveFrame1;
                int last = lastBoatMoveFrame1.count(boat.SN) ? lastBoatMoveFrame1[boat.SN] : -9999;
                if(info.GameFrame - last > 45){
                    Point tgt = findNextFishingExploreTarget(info);
                    if(tgt.x != -1){
                        ai->HumanMove(boat.SN, tgt.x * BLOCKSIDELENGTH, tgt.y * BLOCKSIDELENGTH);
                        ai->DebugText("Fishing boat " + to_string(boat.SN) + " exploring (upgrade phase) to (" + to_string(tgt.x) + "," + to_string(tgt.y) + ")");
                        lastBoatMoveFrame1[boat.SN] = info.GameFrame;
                    }
                }
            }
        }
    }
}

// 阶段2：工具时代。此阶段的策略（例如，海军控制和探索）在此定义。
void executeStage2_ToolAgeEconomyAndNavy(AI *ai, const tagInfo &info) // Renamed from executeStage1_NavalControl
{
    // 舰船位置和卡住状态跟踪（静态变量，保持跨帧状态）
    static std::unordered_map<int, Point> last_pos;
    static std::unordered_map<int, int> stuck_frames;
    const int STUCK_THRESHOLD = 180; // 降低卡住阈值，便于更快切换目标（约3秒）
    static int last_combat_frame = -1; // 最近一次编队攻击帧

    
    // 可调参数
    const int TARGET_FARM_NUM = 4;          // 先准备 6 块农田
    const int TARGET_WARSHIP_NUM = g_ai_state.warship_batch_size; // 目标战船数量与批次保持一致

    // 拷贝一份可用空闲农民列表（会在过程中 pop_back）
    auto available_idle_farmers = g_ai_state.idleFarmerSNs;

    // 计算可支配资源（扣除已预留木材）
    int temp_wood  = info.Wood  - g_ai_state.reserved_wood;
    int temp_meat  = info.Meat;
    int temp_stone = info.Stone;
    if(temp_wood < 0) temp_wood = 0;

    //------------------------------------------------------------------
    // 1. 快速扫描我方建筑与军队现状
    //------------------------------------------------------------------
    bool has_market      = false;
    bool has_granary     = false; // Added: Check for granary
    int  farm_count      = 0;
    int  house_count       = 0;
    int  completed_docks = 0;

    const tagBuilding* first_market_ptr = nullptr;

    for(const auto &bd_pair : g_ai_state.buildings)
    {
        const tagBuilding &bd = bd_pair.second;
        switch(bd.Type)
        {
            case BUILDING_MARKET:
                has_market = true;
                if(!first_market_ptr) first_market_ptr = &bd;
                break;
            case BUILDING_GRANARY: // Added: Check for granary
                has_granary = true;
                break;
            case BUILDING_FARM:
                farm_count++;
                break;
            case BUILDING_DOCK:
                if(bd.Percent == 100) completed_docks++;
                break;
            case BUILDING_HOME:
                house_count++;
                break;
            default:
                break;
        }
    }
    
    // 造船优先：在经济行动前预留少量资源与人口给战船
    int warship_count_early = 0;
    for (const auto &army : info.armies) {
        if (army.Sort == AT_SHIP) warship_count_early++;
    }
    int pop_used_now = static_cast<int>(info.farmers.size() + info.armies.size());
    const int warship_wood_reserve = (completed_docks > 0 && warship_count_early < TARGET_WARSHIP_NUM)
        ? BUILDING_DOCK_CREATE_SHIP_WOOD : 0; // 为战船预留一艘的木材
    const int transport_wood_reserve = (g_ai_state.enemy_land_found && !g_ai_state.transport_requested && g_ai_state.transport_sn == -1)
        ? BUILDING_DOCK_CREATE_WOOD_BOAT_WOOD : 0; // 敌岸已发现，优先预留运输船木材
    auto wood_available_for_non_war = [&]() {
        int w = info.Wood - g_ai_state.reserved_wood - warship_wood_reserve - transport_wood_reserve;
        return (w < 0 ? 0 : w);
    };

    // 阶段2：造人（带限流与“为战船保留人口位”）
    {
        const tagBuilding* tc = getTownCenter(info);
        static int last_farmer_build_frame2 = -9999; // 限流：避免频繁下单导致刷屏
        // 有船坞且战船未达标时，预留少量人口位给战船，防止卡人口
        const int reserved_pop_for_ships = (completed_docks > 0 && warship_count_early < TARGET_WARSHIP_NUM) ? 2 : 0;
        // 早期略降人口上限，给战船让路；达到目标后恢复到32
        int stage2_farmer_cap = (completed_docks > 0 && warship_count_early < TARGET_WARSHIP_NUM) ? 28 : 32;

        if (tc && static_cast<int>(info.farmers.size()) < stage2_farmer_cap && tc->Project == 0 &&
            temp_meat >= BUILDING_CENTER_CREATEFARMER_FOOD &&
            (pop_used_now + reserved_pop_for_ships) < info.Human_MaxNum &&
            info.GameFrame - last_farmer_build_frame2 > 30)
        {
            int cmdId = ai->BuildingAction(tc->SN, BUILDING_CENTER_CREATEFARMER);
            if (cmdId > 0) {
                temp_meat -= BUILDING_CENTER_CREATEFARMER_FOOD;
                last_farmer_build_frame2 = info.GameFrame;
                static int last_dbg = -9999; // 仅偶尔打印一次，避免刷屏
                if (info.GameFrame - last_dbg > 300) {
                    ai->DebugText("[Stage2] Building farmer (cap " + std::to_string(stage2_farmer_cap) + ")...");
                    last_dbg = info.GameFrame;
                }
            }
        }
    }

    // 让所有空闲渔船去渔场捕捞（使用优化的分配逻辑）
    for (const auto &farmer_pair : g_ai_state.farmers)
    {
        const tagFarmer &boat = farmer_pair.second;
        if (boat.FarmerSort == 2 && boat.NowState == HUMAN_STATE_IDLE)
        {
            // 使用优化的渔船分配逻辑
            int best_fish_sn = -1;
            int min_dock_fish_dist = 9999;
            
            // 找到距离这艘船最近的完成船坞
            int nearest_dock_dist = 9999;
            Point nearest_dock_pos = {-1, -1};
            for (const auto &bd_pair : g_ai_state.buildings) {
                const tagBuilding &dock = bd_pair.second;
                if (dock.Type == BUILDING_DOCK && dock.Percent == 100) {
                    int dist = abs(boat.BlockDR - dock.BlockDR) + abs(boat.BlockUR - dock.BlockUR);
                    if (dist < nearest_dock_dist) {
                        nearest_dock_dist = dist;
                        nearest_dock_pos = {dock.BlockDR, dock.BlockUR};
                    }
                }
            }
            
            // 如果找到了船坞，优先选择距离该船坞最近的渔场
            if (nearest_dock_pos.x != -1) {
                for (const auto &resource : info.resources) {
                    if (resource.Type == RESOURCE_FISH) {
                        int dock_fish_dist = abs(nearest_dock_pos.x - resource.BlockDR) + 
                                           abs(nearest_dock_pos.y - resource.BlockUR);
                        if (dock_fish_dist < min_dock_fish_dist) {
                            min_dock_fish_dist = dock_fish_dist;
                            best_fish_sn = resource.SN;
                        }
                    }
                }
            }
            
            // 如果没找到合适的，使用原有逻辑
            if (best_fish_sn == -1) {
                best_fish_sn = findNearestResource({boat.BlockDR, boat.BlockUR}, RESOURCE_FISH, info);
            }
            
            if (best_fish_sn != -1) {
                ai->HumanAction(boat.SN, best_fish_sn);
                ai->DebugText("Sent fishing boat to optimized area during upgrade (dock-distance: " + to_string(min_dock_fish_dist) + ")");
            } else {
                static std::unordered_map<int,int> lastBoatMoveFrame2;
                int last = lastBoatMoveFrame2.count(boat.SN) ? lastBoatMoveFrame2[boat.SN] : -9999;
                if(info.GameFrame - last > 45){
                    Point tgt = findNextFishingExploreTarget(info);
                    if(tgt.x != -1){
                        ai->HumanMove(boat.SN, tgt.x * BLOCKSIDELENGTH, tgt.y * BLOCKSIDELENGTH);
                        ai->DebugText("Fishing boat " + to_string(boat.SN) + " exploring (tool age) to (" + to_string(tgt.x) + "," + to_string(tgt.y) + ")");
                        lastBoatMoveFrame2[boat.SN] = info.GameFrame;
                    }
                }
            }
        }
    }

    // 兵营
    if (!building_type_exists(BUILDING_ARMYCAMP) &&
        !g_ai_state.idleFarmerSNs.empty() &&
        temp_wood >= BUILD_ARMYCAMP_WOOD &&
        pendingCnt(BUILDING_ARMYCAMP) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_ARMYCAMP, g_ai_state.idleFarmerSNs.back(), info);
        if(pos.x != -1){
            int builder = g_ai_state.idleFarmerSNs.back();
            g_ai_state.idleFarmerSNs.pop_back();
            if( tryOrderBuilding(ai, builder, BUILDING_ARMYCAMP, pos.x, pos.y) ){
                temp_wood -= BUILD_ARMYCAMP_WOOD;
                ai->DebugText("Prepare for the Age of Upgrades, building barracks...");
            }
        }
    }

    //------------------------------------------------------------------
    // 2. 确保谷仓存在（市场的前置条件，且可能在第一阶段未建成）
    //------------------------------------------------------------------
    if (!has_granary && !available_idle_farmers.empty() &&
        temp_wood >= BUILD_GRANARY_WOOD &&
        pendingCnt(BUILDING_GRANARY) == 0)
    {
        Point pos = findPlacement(ai, BUILDING_GRANARY, available_idle_farmers.back(), info);
        if (pos.x != -1)
        {
            int builder = available_idle_farmers.back();
            available_idle_farmers.pop_back();
            if (tryOrderBuilding(ai, builder, BUILDING_GRANARY, pos.x, pos.y))
            {
                temp_wood -= BUILD_GRANARY_WOOD;
                ai->DebugText("Stage 2: Building a granary (if not present).");
                return; // 优先建造谷仓，本帧不再执行其他复杂逻辑
            }
        }
    }


    //------------------------------------------------------------------
    // 3. 建造市场（若还没有，且谷仓已存在或正在建造）
    //------------------------------------------------------------------
    static int last_market_attempt_frame = -1;
    bool can_attempt_market = (info.GameFrame - last_market_attempt_frame > 180); // 3秒冷却
    
    if(!has_market && !available_idle_farmers.empty() &&
       can_attempt_market &&
       wood_available_for_non_war() >= BUILD_MARKET_WOOD + 30 && // 为战船预留木材后再考虑建市集
       pendingCnt(BUILDING_MARKET) == 0 &&
       (has_granary || pendingCnt(BUILDING_GRANARY) > 0))
    {
        int builder_sn = available_idle_farmers.back();
        Point pos = findPlacement(ai, BUILDING_MARKET, builder_sn, info);
        if(pos.x != -1)
        {
            if( tryOrderBuilding(ai, builder_sn, BUILDING_MARKET, pos.x, pos.y) )
            {
                available_idle_farmers.pop_back();
                temp_wood -= BUILD_MARKET_WOOD;
                ai->DebugText("Stage 2: Ordering a builder to construct a market.");
                return; // 优先建造市场，本帧不再执行其他复杂逻辑
            } else {
                last_market_attempt_frame = info.GameFrame; // 失败时设置冷却
            }
        } else {
            last_market_attempt_frame = info.GameFrame; // 找不到位置也冷却
        }
    }

    //------------------------------------------------------------------
    // 4. 建造农田（需要市场已完成或正在建造）
    //------------------------------------------------------------------
    static int last_farm_attempt_frame = -1;
    bool can_attempt_farm = (info.GameFrame - last_farm_attempt_frame > 240); // 4秒冷却
    
    int farms_pending = pendingCnt(BUILDING_FARM);
    while( (farm_count + farms_pending) < TARGET_FARM_NUM &&
           has_market && first_market_ptr && first_market_ptr->Percent == 100 &&
           !available_idle_farmers.empty() &&
           can_attempt_farm &&
           // 避免与战船争抢：为战船预留一艘的木材
           (wood_available_for_non_war() >= BUILD_FARM_WOOD + 20))
    {
        int builder_sn = available_idle_farmers.back();
        Point pos = findPlacement(ai, BUILDING_FARM, builder_sn, info);
        if(pos.x == -1) {
            last_farm_attempt_frame = info.GameFrame; // 找不到位置也冷却
            break;
        }

        if( tryOrderBuilding(ai, builder_sn, BUILDING_FARM, pos.x, pos.y) )
        {
            available_idle_farmers.pop_back();
            temp_wood -= BUILD_FARM_WOOD;
            farms_pending++;
            ai->DebugText("Planning a new farm.");
        }
        else
        {
            last_farm_attempt_frame = info.GameFrame; // 失败时设置冷却
            break;
        }
    }

    //------------------------------------------------------------------
    // 5. 市场科技：木材升级（提高采集效率 & 战船射程）
    //------------------------------------------------------------------
    if(first_market_ptr && first_market_ptr->Percent == 100 && first_market_ptr->Project == 0 &&
       !g_ai_state.wood_upgrade_done &&
       temp_meat >= BUILDING_MARKET_WOOD_UPGRADE_FOOD &&
       temp_wood >= BUILDING_MARKET_WOOD_UPGRADE_WOOD )
    {
        ai->BuildingAction(first_market_ptr->SN, BUILDING_MARKET_WOOD_UPGRADE);
        g_ai_state.wood_upgrade_done = true;
        temp_meat -= BUILDING_MARKET_WOOD_UPGRADE_FOOD;
        temp_wood -= BUILDING_MARKET_WOOD_UPGRADE_WOOD;
        ai->DebugText("*************************************************Researching wood-cutting upgrade at market.*************************************************");
    }

    /// ------ 人口保护：人口接近上限时立即造房子 ------
    // 房屋建造冷却：避免资源不足或位置不足时疯狂重试
    static int last_house_attempt_frame = -1;
    bool can_attempt_house = (info.GameFrame - last_house_attempt_frame > 240); // 4秒冷却，降噪
    
    int pop_used = static_cast<int>(info.farmers.size() + info.armies.size());
    if (pop_used >= info.Human_MaxNum - 1               // 快顶满
        && can_attempt_house
        && info.Wood - g_ai_state.reserved_wood >= BUILD_HOUSE_WOOD + 10 // 更严格的资源检查，预留余量
        && !available_idle_farmers.empty()
        && (house_count + pendingCnt(BUILDING_HOME) < 8) // 总房屋上限8
        && pendingCnt(BUILDING_HOME) < 1)               // 仿阶段0，仅排1个
    {
        int builderSN = available_idle_farmers.back();
        available_idle_farmers.pop_back();
        int sizeX, sizeY; getBuildingSize(BUILDING_HOME, sizeX, sizeY);
        Point p = findPlacement(ai, BUILDING_HOME, builderSN, info);
        if(p.x == -1){
            // 以住宅区中心为起点扩圈 60
            p = findPlacementAroundPoint(sizeX, sizeY, {g_ai_state.residentialZone.centerX, g_ai_state.residentialZone.centerY}, 60, info);
        }
        if(p.x == -1){
            // 仍失败 → 以建造者位置为起点再搜
            const tagFarmer &builderRef = g_ai_state.farmers[builderSN];
            p = findPlacementAroundPoint(sizeX, sizeY, {builderRef.BlockDR, builderRef.BlockUR}, 60, info);
        }

        if (p.x != -1 && tryOrderBuilding(ai, builderSN, BUILDING_HOME, p.x, p.y))
        {
            temp_wood -= BUILD_HOUSE_WOOD;
            // 降低刷屏频率：仅在首次或间隔较长时输出
            static int last_house_dbg = -9999;
            if(info.GameFrame - last_house_dbg > 600){
                ai->DebugText("Population cap near max — building extra houses.");
                last_house_dbg = info.GameFrame;
            }
        }else{
            // 建造失败，将村民放回空闲列表，方便下次使用
            g_ai_state.idleFarmerSNs.push_back(builderSN);
            last_house_attempt_frame = info.GameFrame; // 失败时设置冷却
        }
    }

    // 兵营
    // ------------------------------------------------------------------
    // 6. 造战船
    // ------------------------------------------------------------------
    int warship_count = 0;
    for(const auto &army : info.armies)
    {
        if(army.Sort == AT_SHIP) warship_count++;
    }

    int pop_used_shipPhase = static_cast<int>(info.farmers.size() + info.armies.size());

    // 战船建造冷却：避免资源不足时疯狂重试
    static int last_warship_attempt_frame = -1;
    bool can_attempt_warship = (info.GameFrame - last_warship_attempt_frame > 60); // 1秒冷却，加快尝试
    
    for(const auto &bd_pair : g_ai_state.buildings)
    {
        // 驻扎后突破生产上限，持续生产战船
        if(warship_count >= TARGET_WARSHIP_NUM && !g_ai_state.fleet_guard_mode) break;

        const tagBuilding &dock = bd_pair.second;
        if(dock.Type == BUILDING_DOCK && dock.Percent == 100 && dock.Project == 0)
        {
            // 更严格的资源检查：预留安全余量，并对房屋/农田保持最低军备预算
            // 轻量再平衡：预留 ship_min_wood，避免被房屋/农田抢占全部木材
            const int ship_min_wood = BUILDING_DOCK_CREATE_SHIP_WOOD + 10;
            if(can_attempt_warship && 
               info.Wood - g_ai_state.reserved_wood >= ship_min_wood &&
               pop_used_shipPhase < info.Human_MaxNum)
            {
                int cmdId = ai->BuildingAction(dock.SN, BUILDING_DOCK_CREATE_SHIP);
                if(cmdId > 0){
                    temp_wood -= BUILDING_DOCK_CREATE_SHIP_WOOD;
                    warship_count++;
                    last_warship_attempt_frame = info.GameFrame; // 记录尝试时间
                    if(g_ai_state.fleet_guard_mode){
                        ai->DebugText("A dock starts building a warship for continuous reinforcement at rally point.");
                    } else {
                        ai->DebugText("A dock starts building a warship.");
                    }
                } else {
                    last_warship_attempt_frame = info.GameFrame; // 失败也要冷却
                }
            }
        }
    }

    // ------------------------------------------------------------------
    // 6.5 战船编队出发逻辑（严格按批次 4 艘）
    // ------------------------------------------------------------------
    {
        // ---------- (1) 先清理 launched_warship_SNs 中已阵亡的船 ----------
        std::unordered_set<int> alive_launched;
        for(const auto &army : info.armies){
            if(army.Sort == AT_SHIP && g_ai_state.launched_warship_SNs.count(army.SN)){
                alive_launched.insert(army.SN);
            }
        }
        g_ai_state.launched_warship_SNs.swap(alive_launched);
        
        // ---------- (2) 收集尚未出发且空闲的战船 ----------
        std::vector<int> idle_unlaunched;
        for(const auto &army : info.armies){
            if(army.Sort == AT_SHIP &&
               g_ai_state.launched_warship_SNs.count(army.SN) == 0 &&
               army.NowState == HUMAN_STATE_IDLE){
                idle_unlaunched.push_back(army.SN);
            }
        }
        
        const int BATCH_SIZE = g_ai_state.warship_batch_size; // 期望 4 艘/批
        int alive_cnt = static_cast<int>(g_ai_state.launched_warship_SNs.size());

        // ---------- (3) 重新设计的批次管理：保证编队紧凑性 ----------
        if(alive_cnt == 0){
            // 初次出发：先集结再出发，避免一个个送
            if(idle_unlaunched.size() >= BATCH_SIZE){
                if(!g_ai_state.regrouping_mode){
                    g_ai_state.regrouping_mode = true;
                    // 选择第一个完工船坞附近的安全海域作为集结点
                    const tagBuilding* first_dock = nullptr;
                    for(const auto &bd : g_ai_state.buildings){
                        if(bd.second.Type == BUILDING_DOCK && bd.second.Percent == 100){
                            first_dock = &bd.second;
                            break;
                        }
                    }
                    if(first_dock){
                        for(int r = 8; r <= 15; ++r){
                            for(int i = 0; i < 8*r; ++i){
                                Point test = getSpiralPoint(first_dock->BlockDR, first_dock->BlockUR, i, r);
                                if(test.x >= 10 && test.x < 118 && test.y >= 10 && test.y < 118 &&
                                   (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN){
                                    g_ai_state.regrouping_point = test;
                                    ai->DebugText("Prelaunch rally point set at (" + std::to_string(test.x) + "," + std::to_string(test.y) + ")");
                                    goto prelaunch_point_found;
                                }
                            }
                        }
                        prelaunch_point_found:;
                    }
                }
                // 检查是否已集结到位
                int ships_at_regrouping_point = 0;
                if(g_ai_state.regrouping_point.x != -1){
                    for(const auto &ship : info.armies){
                        if(ship.Sort == AT_SHIP){
                            int dist = abs(ship.BlockDR - g_ai_state.regrouping_point.x) + 
                                      abs(ship.BlockUR - g_ai_state.regrouping_point.y);
                            if(dist <= 3) ships_at_regrouping_point++;
                        }
                    }
                }
                if(ships_at_regrouping_point >= BATCH_SIZE){
                    // 选取距离集结点最近的 BATCH_SIZE 艘作为出发编队
                    g_ai_state.launched_warship_SNs.clear();
                    vector<pair<int,int>> ship_distances;
                    for(const auto &ship : info.armies){
                        if(ship.Sort == AT_SHIP){
                            int dist = abs(ship.BlockDR - g_ai_state.regrouping_point.x) + 
                                      abs(ship.BlockUR - g_ai_state.regrouping_point.y);
                            ship_distances.push_back({ship.SN, dist});
                        }
                    }
                    sort(ship_distances.begin(), ship_distances.end(), 
                         [](const pair<int,int> &a, const pair<int,int> &b){ return a.second < b.second; });
                    for(int i = 0; i < std::min(BATCH_SIZE, (int)ship_distances.size()); ++i){
                        g_ai_state.launched_warship_SNs.insert(ship_distances[i].first);
                        stuck_frames[ship_distances[i].first] = 0;
                    }
                    ai->DebugText("Fleet assembled. Launching " + std::to_string(BATCH_SIZE) + " warships together.");
                    // 重置探索系统
                    g_ai_state.exploration_phase = 0;
                    g_ai_state.shared_exploration_target = {-1,-1};
                    g_ai_state.enemy_coastline_start = {-1,-1};
                    g_ai_state.coastline_search_angle = 0;
                    // 退出集结模式
                    g_ai_state.regrouping_mode = false;
                    g_ai_state.regrouping_point = {-1,-1};
                }
            }
        }else if(alive_cnt <= 2 && idle_unlaunched.size() >= 2){
            // 损失惨重（只剩1-2艘），启动重组模式
            if(!g_ai_state.regrouping_mode){
                ai->DebugText("Heavy losses detected (" + std::to_string(alive_cnt) + " remaining). Initiating regrouping mode.");
                g_ai_state.regrouping_mode = true;
                g_ai_state.shared_exploration_target = {-1,-1}; // 重置探索目标
                
                // 设置集结点（船坞附近的安全海域）
                const tagBuilding* first_dock = nullptr;
                for(const auto &bd : g_ai_state.buildings){
                    if(bd.second.Type == BUILDING_DOCK && bd.second.Percent == 100){
                        first_dock = &bd.second;
                        break;
                    }
                }
                
                if(first_dock){
                    // 在船坞附近找一个海洋集结点
                    for(int r = 8; r <= 15; ++r){
                        for(int i = 0; i < 8*r; ++i){
                            Point test = getSpiralPoint(first_dock->BlockDR, first_dock->BlockUR, i, r);
                            if(test.x >= 10 && test.x < 118 && test.y >= 10 && test.y < 118 &&
                               (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN){
                                g_ai_state.regrouping_point = test;
                                ai->DebugText("Set regrouping point at (" + std::to_string(test.x) + "," + std::to_string(test.y) + ")");
                                goto found_regrouping_point;
                            }
                        }
                    }
                    found_regrouping_point:;
                }
            }
            
            // 如果有足够的船只（包括新船和幸存者），准备重新编队
            if(idle_unlaunched.size() + alive_cnt >= BATCH_SIZE){
                // 检查有多少船只已经到达集结点
                int ships_at_regrouping_point = 0;
                if(g_ai_state.regrouping_point.x != -1){
                    for(const auto &ship : info.armies){
                        if(ship.Sort == AT_SHIP){
                            int dist = abs(ship.BlockDR - g_ai_state.regrouping_point.x) + 
                                      abs(ship.BlockUR - g_ai_state.regrouping_point.y);
                            if(dist <= 3) ships_at_regrouping_point++;
                        }
                    }
                }
                
                // 如果足够船只已集结，正式启动新编队
                if(ships_at_regrouping_point >= BATCH_SIZE){
                    g_ai_state.launched_warship_SNs.clear();
                    int launched_count = 0;
                    
                    // 选择距离集结点最近的4艘船
                    vector<pair<int, int>> ship_distances; // (SN, distance)
                    for(const auto &ship : info.armies){
                        if(ship.Sort == AT_SHIP){
                            int dist = abs(ship.BlockDR - g_ai_state.regrouping_point.x) + 
                                      abs(ship.BlockUR - g_ai_state.regrouping_point.y);
                            ship_distances.push_back({ship.SN, dist});
                        }
                    }
                    sort(ship_distances.begin(), ship_distances.end(), 
                         [](const pair<int,int> &a, const pair<int,int> &b){ return a.second < b.second; });
                    
                    for(int i = 0; i < std::min(BATCH_SIZE, (int)ship_distances.size()); ++i){
                        g_ai_state.launched_warship_SNs.insert(ship_distances[i].first);
                        launched_count++;
                    }
                    
                    ai->DebugText("Regrouping complete! New tight formation with " + std::to_string(launched_count) + " warships.");
                    g_ai_state.regrouping_mode = false;
                    g_ai_state.regrouping_point = {-1, -1};
                    g_ai_state.exploration_phase = 0;
                    g_ai_state.shared_exploration_target = {-1, -1}; // 确保探索目标重置
                    // 清理重组舰队的stuck_frames，确保全新开始
                    for(int i = 0; i < std::min(BATCH_SIZE, (int)ship_distances.size()); ++i){
                        stuck_frames[ship_distances[i].first] = 0;
                    }
                    ai->DebugText("Reset stuck_frames for regrouped fleet");
                }
            }
        }else if(alive_cnt < BATCH_SIZE){
            // 补充策略：
            // - 若已有舰队≥3艘，允许补足到BATCH_SIZE
            // - 若不足3艘，则等待新船≥3艘再一起加入（避免散兵）
            if(alive_cnt >= 3){
                int need = std::min(BATCH_SIZE - alive_cnt, static_cast<int>(idle_unlaunched.size()));
                if(need > 0) {
                    for(int i = 0; i < need; ++i){ g_ai_state.launched_warship_SNs.insert(idle_unlaunched[i]); }
                    ai->DebugText("Reinforcing fleet by " + std::to_string(need) + " ships to keep formation.");
                }
            } else if(static_cast<int>(idle_unlaunched.size()) >= 3){
                // 集齐3艘再加入，增强同步
                for(int i=0;i<3;++i){ g_ai_state.launched_warship_SNs.insert(idle_unlaunched[i]); }
                ai->DebugText("Adding 3 new ships to re-form a minimal core.");
            }
        }
        
        // 如果舰队已驻扎且有空闲新战船，让它们前往驻扎位置
        if(g_ai_state.fleet_guard_mode && g_ai_state.fleet_rally.x != -1 && !idle_unlaunched.empty()){
            for(int ship_sn : idle_unlaunched){
                // 检查是否已经在驻扎位置附近
                bool already_at_rally = false;
                for(const auto &ship : info.armies){
                    if(ship.SN == ship_sn && ship.Sort == AT_SHIP){
                        int dist_to_rally = abs(ship.BlockDR - g_ai_state.fleet_rally.x) + 
                                          abs(ship.BlockUR - g_ai_state.fleet_rally.y);
                        if(dist_to_rally <= 5){
                            already_at_rally = true;
                            break;
                        }
                    }
                }
                
                if(!already_at_rally){
                    ai->HumanMove(ship_sn, g_ai_state.fleet_rally.x * BLOCKSIDELENGTH, 
                                 g_ai_state.fleet_rally.y * BLOCKSIDELENGTH);
                    ai->DebugText("New warship " + to_string(ship_sn) + " moving to fleet rally point (" + 
                                 to_string(g_ai_state.fleet_rally.x) + "," + to_string(g_ai_state.fleet_rally.y) + ")");
                }
            }
        }
    }
    // ------------------------------------------------------------------
    // 6.3 发现敌岸后生产运输船
    // ------------------------------------------------------------------
    static int last_transport_check_frame = -1;
    if(info.GameFrame - last_transport_check_frame > 600) { // 每10秒检查一次
        if(g_ai_state.enemy_land_found) {
            ai->DebugText("Enemy land found, checking transport production. Requested: " +
                         to_string(g_ai_state.transport_requested) +
                         ", Transport SN: " + to_string(g_ai_state.transport_sn));
        } else {
            ai->DebugText("Enemy land not found yet, cannot produce transport ship.");
        }
        last_transport_check_frame = info.GameFrame;
    }

    if(g_ai_state.enemy_land_found && !g_ai_state.transport_requested){
        for(const auto &bd_pair : g_ai_state.buildings){
            const tagBuilding &dock = bd_pair.second;
            if(dock.Type == BUILDING_DOCK && dock.Percent == 100 && dock.Project == 0){
                // 运输船优先级很高，使用实际木材而不是temp_wood（扣除预留后的）
                // 同时严禁此时建造战船：通过跳过战船建造循环中的资源判断，我们已经预留了木材
                if(info.Wood >= BUILDING_DOCK_CREATE_WOOD_BOAT_WOOD && pop_used_shipPhase < info.Human_MaxNum){
                    int cmdId = ai->BuildingAction(dock.SN, BUILDING_DOCK_CREATE_WOOD_BOAT);
                    if(cmdId > 0){
                        // 运输船使用实际木材，所以需要从temp_wood中扣除，但要确保不会变成负数
                        temp_wood = max(0, temp_wood - BUILDING_DOCK_CREATE_WOOD_BOAT_WOOD);
                        g_ai_state.transport_requested = true;
                        ai->DebugText("Ordering a dock to build a transport ship.");
                        break;
                    } else {
                        ai->DebugText("Failed to order transport ship from dock " + to_string(dock.SN));
                    }
                } else {
                    // 添加节流机制，避免刷屏
                    static int last_transport_fail_debug_frame = -1;
                    if(info.GameFrame - last_transport_fail_debug_frame > 300) { // 5秒冷却
                        ai->DebugText("Cannot build transport: wood=" + to_string(info.Wood) +
                                     " (need " + to_string(BUILDING_DOCK_CREATE_WOOD_BOAT_WOOD) +
                                     "), reserved=" + to_string(g_ai_state.reserved_wood) +
                                     ", pop=" + to_string(pop_used_shipPhase) +
                                     "/" + to_string(info.Human_MaxNum));
                        last_transport_fail_debug_frame = info.GameFrame;
                    }
                }
            }
        }
    }
    // ------------------------------------------------------------------
    // 7. 精简的战船探索逻辑
    // ------------------------------------------------------------------
    // 查找距离岸边1-2格的海洋位置（避免卡住）
    auto findSafeOcean = [&](Point target, const tagInfo& info) -> Point {
        for(int r = 2; r <= 30; ++r) { // 从2格开始搜索
            for(int i = 0; i < 8 * r; i += 2) { // 减少搜索密度
                Point test = getSpiralPoint(target.x, target.y, i, r);
                if(test.x >= 2 && test.x < 126 && test.y >= 2 && test.y < 126 &&
                   (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN) {
                    // 计算到最近陆地的距离
                    int min_land_dist = 999;
                    for(int dx = -3; dx <= 3; ++dx) {
                        for(int dy = -3; dy <= 3; ++dy) {
                            int nx = test.x + dx, ny = test.y + dy;
                            if(nx >= 0 && nx < 128 && ny >= 0 && ny < 128) {
                                int typ = (*info.theMap)[nx][ny].type;
                                if(typ == MAPPATTERN_GRASS || typ == MAPPATTERN_DESERT) {
                                    int dist = abs(dx) + abs(dy); // 曼哈顿距离
                                    min_land_dist = min(min_land_dist, dist);
                                }
                            }
                        }
                    }
                    // 选择距离陆地1-2格的位置
                    if(min_land_dist >= 1 && min_land_dist <= 2) return test;
                }
            }
        }
        return {-1, -1};
    };
    
    // 简化探索逻辑：不使用全局timeout，让coastline exploration自己管理状态
    
    // 清理死亡船只的SN并重新选择领队
    unordered_set<int> alive_launched_sns;
    int current_leader_sn = -1;
    
    for(const auto &ship : info.armies) {
        if(ship.Sort == AT_SHIP && g_ai_state.launched_warship_SNs.count(ship.SN) > 0) {
            alive_launched_sns.insert(ship.SN);  // 记录还活着的已发射船只
            if(current_leader_sn == -1 || ship.SN < current_leader_sn) {
                current_leader_sn = ship.SN;  // 选择SN最小的作为新领队
            }
        }
    }
    
    // 更新launched_warship_SNs，移除死亡船只
    g_ai_state.launched_warship_SNs = alive_launched_sns;
    
    // 如果领队死亡或没有船，重置探索状态
     static int last_leader_sn = -1;
     if(current_leader_sn != last_leader_sn) {
         if(last_leader_sn != -1) {
             ai->DebugText("Leader changed from " + to_string(last_leader_sn) + " to " + to_string(current_leader_sn) + ", resetting formation");
             g_ai_state.shared_exploration_target = {-1, -1}; // 重置目标，让新领队重新计算
         }
         last_leader_sn = current_leader_sn;
     }
     
     // 缓存队长当前坐标，供队形跟随使用
     Point leader_pos_cache = {-1, -1};
     if(current_leader_sn != -1){
         for(const auto &s2 : info.armies){
             if(s2.Sort == AT_SHIP && s2.SN == current_leader_sn){
                 leader_pos_cache = {s2.BlockDR, s2.BlockUR};
                 break;
             }
         }
     }
     
     for(const auto &ship : info.armies)
     {
        if(ship.Sort != AT_SHIP) continue;
        
        // ========== 防卡机制：简化版 ==========
        bool is_launched = g_ai_state.launched_warship_SNs.count(ship.SN) > 0;
        // 使用全局计算的领队身份
        bool is_leader = (ship.SN == current_leader_sn);

        if(is_launched) {
            Point cur_pos = {ship.BlockDR, ship.BlockUR};
            
            // 避免在自家近岸就误触发"发现敌岸" - 以dock为基准
            bool far_from_dock = true;
            for(const auto &bd_pair : g_ai_state.buildings){
                const tagBuilding &dock = bd_pair.second;
                if(dock.Type == BUILDING_DOCK && dock.Percent == 100){
                    int dist_dock = abs(ship.BlockDR - dock.BlockDR) + abs(ship.BlockUR - dock.BlockUR);
                    if(dist_dock < 35){
                        far_from_dock = false;
                        break;
                    }
                }
            }

                            // 简化的stuck检测机制：仅在远离dock后生效，且避开战斗期，且有移动目标时才累计
                if(far_from_dock && g_ai_state.shared_exploration_target.x != -1) {
                    bool recently_in_combat = (info.GameFrame - last_combat_frame <= 120);
                    bool movable_state = (ship.NowState == HUMAN_STATE_IDLE || ship.NowState == HUMAN_STATE_WALKING);
                    if(recently_in_combat) {
                        // 战斗期间不累计卡住，避免战斗时刷stuck
                        stuck_frames[ship.SN] = 0;
                    } else if(movable_state && last_pos.count(ship.SN) &&
                              abs(cur_pos.x - last_pos[ship.SN].x) + abs(cur_pos.y - last_pos[ship.SN].y) < 2) {
                        stuck_frames[ship.SN]++;
                        if(is_leader && stuck_frames[ship.SN] % 30 == 0) {
                            ai->DebugText("STUCK DETECTION: Leader stuck_frames=" + to_string(stuck_frames[ship.SN]) +
                                          ", pos=(" + to_string(cur_pos.x) + "," + to_string(cur_pos.y) + ")");
                        }
                    } else if(movable_state) {
                        if(stuck_frames[ship.SN] > 0 && is_leader) {
                            ai->DebugText("STUCK DETECTION: Leader movement detected, resetting stuck_frames from " + to_string(stuck_frames[ship.SN]));
                        }
                        stuck_frames[ship.SN] = 0;
                    }
                // 修复的stuck处理逻辑：保留探索阶段状态；对角阶段切换下一个候选；已发现敌岸则转入沿岸探索
                if(stuck_frames[ship.SN] > STUCK_THRESHOLD){
                    if(is_leader){
                        if(!g_ai_state.enemy_land_found){
                            if(g_ai_state.exploration_phase == 0 && !g_ai_state.symmetric_targets.empty()){
                                g_ai_state.current_target_index = (g_ai_state.current_target_index + 1) % (int)g_ai_state.symmetric_targets.size();
                                Point nxt = g_ai_state.symmetric_targets[g_ai_state.current_target_index];
                                g_ai_state.shared_exploration_target = nxt;
                                g_ai_state.total_exploration_frames = -1;
                                ai->DebugText("Leader stuck > threshold, switching to next diagonal target (" +
                                              to_string(nxt.x) + "," + to_string(nxt.y) + "), index=" +
                                              to_string(g_ai_state.current_target_index));
                            }
                        } else {
                            // 已发现敌岸：切换到沿岸探索
                            g_ai_state.exploration_phase = 1;
                            g_ai_state.shared_exploration_target = {-1,-1};
                            g_ai_state.total_exploration_frames = -1;
                            ai->DebugText("Leader stuck > threshold near enemy shore, switching to coastline exploration phase.");
                        }
                    }
                    stuck_frames[ship.SN] = 0; // 重置计数，避免连续触发
                }
            } else {
                // 仍在dock附近，重置stuck计数
                stuck_frames[ship.SN] = 0;
            }
            
            last_pos[ship.SN] = cur_pos;
        }
        
        // ---------- 敌人检测与锁定 ----------
        // 检查是否已出发编队
        is_launched = g_ai_state.launched_warship_SNs.count(ship.SN) > 0;
        
        // 只有已出发的战船才执行敌人检测与攻击：同批共享目标
        if(is_launched){
            auto exists=[&](int sn){
                for(const auto&a:info.enemy_armies)    if(a.SN==sn) return true;
                for(const auto&b:info.enemy_buildings) if(b.SN==sn) return true;
                for(const auto&f:info.enemy_farmers)   if(f.SN==sn) return true;
                return false;
            };
            // 若无共享目标或目标失效，则由领队重新选择一个“舰队共享目标”
            if(is_leader){
                if(g_ai_state.current_fleet_target_sn == -1 || !exists(g_ai_state.current_fleet_target_sn)){
                    int candidate = -1; int best_dist = 9999;
                    // 以舰队中心为参考，挑最近的可攻击目标
                    int cx=0, cy=0, cnt=0; for(const auto &other:info.armies){ if(other.Sort==AT_SHIP && g_ai_state.launched_warship_SNs.count(other.SN)){ cx+=other.BlockDR; cy+=other.BlockUR; ++cnt; } }
                    if(cnt>0){ cx/=cnt; cy/=cnt; }
                    auto consider=[&](int sn,int x,int y){ int d=abs(cx-x)+abs(cy-y); if(d<best_dist && d<=22){ best_dist=d; candidate=sn; } };
                    for(const auto&e:info.enemy_armies)    consider(e.SN,e.BlockDR,e.BlockUR);
                    for(const auto&e:info.enemy_buildings) consider(e.SN,e.BlockDR,e.BlockUR);
                    for(const auto&e:info.enemy_farmers)   consider(e.SN,e.BlockDR,e.BlockUR);
                    g_ai_state.current_fleet_target_sn = candidate;
                    g_ai_state.fleet_target_last_seen_frame = info.GameFrame;
                }
            }
            // 非领队：如果有共享目标且在有效范围内，则攻击共享目标
            if(g_ai_state.current_fleet_target_sn != -1){
                // 距离校验（对每艘也作一次容差判断）
                int tx=-1, ty=-1; bool found=false;
                for(const auto&e:info.enemy_armies){ if(e.SN==g_ai_state.current_fleet_target_sn){ tx=e.BlockDR; ty=e.BlockUR; found=true; break; } }
                if(!found) for(const auto&e:info.enemy_buildings){ if(e.SN==g_ai_state.current_fleet_target_sn){ tx=e.BlockDR; ty=e.BlockUR; found=true; break; } }
                if(!found) for(const auto&e:info.enemy_farmers){ if(e.SN==g_ai_state.current_fleet_target_sn){ tx=e.BlockDR; ty=e.BlockUR; found=true; break; } }
                if(found){
                    int d = (ship.BlockDR-tx)*(ship.BlockDR-tx)+(ship.BlockUR-ty)*(ship.BlockUR-ty);
                    if(d <= 22*22){
                        // 只有当战船不在攻击状态，或者攻击目标不是当前共享目标时，才发送攻击命令
                        bool should_attack = false;
                        if(ship.NowState != HUMAN_STATE_ATTACKING) {
                            should_attack = true;
                        } else if(ship.WorkObjectSN != g_ai_state.current_fleet_target_sn) {
                            should_attack = true;
                        }

                        if(should_attack) {
                            ai->HumanAction(ship.SN, g_ai_state.current_fleet_target_sn);
                        }
                        last_combat_frame = info.GameFrame;
                        continue; // 战斗中不做移动/探索
                    }
                }
            }
        }
        
        // ========== 以下逻辑只对 IDLE 状态战船执行 ==========
        if(ship.NowState != HUMAN_STATE_IDLE) continue;
         
                // 未出发的战船：根据模式决定行为
        if(g_ai_state.launched_warship_SNs.count(ship.SN) == 0) {
            if(g_ai_state.regrouping_mode && g_ai_state.regrouping_point.x != -1) {
                // 重组模式：所有船只前往集结点
                int dist_to_regrouping_point = abs(ship.BlockDR - g_ai_state.regrouping_point.x) + 
                                               abs(ship.BlockUR - g_ai_state.regrouping_point.y);
                if(dist_to_regrouping_point > 3) {
                    ai->HumanMove(ship.SN, g_ai_state.regrouping_point.x * BLOCKSIDELENGTH, 
                                 g_ai_state.regrouping_point.y * BLOCKSIDELENGTH);
                    ai->DebugText("Ship " + to_string(ship.SN) + " moving to regrouping point (" + 
                                 to_string(g_ai_state.regrouping_point.x) + "," + to_string(g_ai_state.regrouping_point.y) + ")");
                }
            } else {
                // 正常模式：推离船坞等待编队
            for(const auto &bd : g_ai_state.buildings) {
                if(bd.second.Type == BUILDING_DOCK && bd.second.Percent == 100) {
                    int dx = ship.BlockDR - bd.second.BlockDR;
                    int dy = ship.BlockUR - bd.second.BlockUR;
                    if(dx*dx + dy*dy <= 9) { // ≤3格
                        // 计算背离大陆的方向
                        Point dock_pos = {bd.second.BlockDR, bd.second.BlockUR};

                        // 检测船坞周围的陆地方向
                        int land_dir_x = 0, land_dir_y = 0;
                        int land_count = 0;

                        for(int check_dx = -2; check_dx <= 2; check_dx++) {
                            for(int check_dy = -2; check_dy <= 2; check_dy++) {
                                int check_x = dock_pos.x + check_dx;
                                int check_y = dock_pos.y + check_dy;
                                if(check_x >= 0 && check_x < 128 && check_y >= 0 && check_y < 128) {
                                    int tile_type = (*info.theMap)[check_x][check_y].type;
                                    if(tile_type == MAPPATTERN_GRASS || tile_type == MAPPATTERN_DESERT) {
                                        land_dir_x += check_dx;
                                        land_dir_y += check_dy;
                                        land_count++;
                                    }
                                }
                            }
                        }

                        // 计算背离陆地的方向
                        int push_dir_x = 0, push_dir_y = 0;
                        if(land_count > 0) {
                            // 背离陆地重心的方向
                            push_dir_x = -(land_dir_x / land_count);
                            push_dir_y = -(land_dir_y / land_count);

                            // 归一化方向
                            if(push_dir_x > 0) push_dir_x = 1;
                            else if(push_dir_x < 0) push_dir_x = -1;
                            if(push_dir_y > 0) push_dir_y = 1;
                            else if(push_dir_y < 0) push_dir_y = -1;
                        }

                        // 沿背离陆地的方向寻找海洋位置
                        bool moved = false;
                        for(int dist = 3; dist <= 8 && !moved; ++dist) {
                            Point target = {
                                ship.BlockDR + push_dir_x * dist,
                                ship.BlockUR + push_dir_y * dist
                            };

                            if(target.x >= 0 && target.x < 128 && target.y >= 0 && target.y < 128 &&
                               (*info.theMap)[target.x][target.y].type == MAPPATTERN_OCEAN) {
                                ai->HumanMove(ship.SN, target.x * BLOCKSIDELENGTH, target.y * BLOCKSIDELENGTH);
                                ai->DebugText("Pushing ship " + to_string(ship.SN) + " away from land to (" + to_string(target.x) + "," + to_string(target.y) + ")");
                                moved = true;
                            }
                        }

                        // 如果背离陆地方向没找到合适位置，使用原来的螺旋搜索作为备用
                        if(!moved) {
                            for(int r = 3; r <= 8 && !moved; ++r) {
                                for(int i = 0; i < 8*r && !moved; ++i) {
                                    Point test = getSpiralPoint(ship.BlockDR, ship.BlockUR, i, r);
                                    if(test.x >= 0 && test.x < 128 && test.y >= 0 && test.y < 128 &&
                                       (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN) {
                                        ai->HumanMove(ship.SN, test.x * BLOCKSIDELENGTH, test.y * BLOCKSIDELENGTH);
                                        ai->DebugText("Fallback: Pushing ship " + to_string(ship.SN) + " to (" + to_string(test.x) + "," + to_string(test.y) + ")");
                                        moved = true;
                                    }
                                }
                            }
                        }
                            break;
                        }
                        }
                    }
                }
            continue; // 未出发舰队暂不执行作战任务
        }
        
        // ========== 简化的敌方检测 ==========
        if(!g_ai_state.enemy_land_found) {
            // 避免在自家近岸就误触发"发现敌岸" - 以dock为基准
            bool far_from_dock = true;
            for(const auto &bd_pair : g_ai_state.buildings){
                const tagBuilding &dock = bd_pair.second;
                if(dock.Type == BUILDING_DOCK && dock.Percent == 100){
                    int dist_dock = abs(ship.BlockDR - dock.BlockDR) + abs(ship.BlockUR - dock.BlockUR);
                    if(dist_dock < 35){
                        far_from_dock = false;
                        break;
                    }
                }
            }
            
            if(far_from_dock){
                // 检测附近是否有陆地
                for(int dx=-6; dx<=6 && !g_ai_state.enemy_land_found; ++dx) {
                    for(int dy=-6; dy<=6 && !g_ai_state.enemy_land_found; ++dy) {
                        int nx = ship.BlockDR + dx, ny = ship.BlockUR + dy;
                        if(nx>=0 && nx<128 && ny>=0 && ny<128) {
                            int tile_type = (*info.theMap)[nx][ny].type;
                                                         if(tile_type == MAPPATTERN_GRASS || tile_type == MAPPATTERN_DESERT) {
                                 // 检查是否为己方陆地 - 如果是则忽略
                                 if (!g_ai_state.ownLand[nx][ny]) {
                                     g_ai_state.enemy_land_found = true;
                                     g_ai_state.enemy_land_pos = {nx, ny};
                                     ai->DebugText("Enemy land found at (" + to_string(nx) + "," + to_string(ny) + ")! Switching to careful exploration.");
                                     ai->DebugText("Will start producing transport ship next cycle.");
                                     break;
                                 }
                             }
                        }
                    }
                }
            }
        }

        // ========== 深海/守备系统 ==========
        if(ship.NowState != HUMAN_STATE_IDLE) continue; // 只有空闲战船参与探索

        // 只有领导者计算新的探索目标
        // 修复：战斗后立即允许重新设置探索目标，避免战船呆立不动
        // 检查是否有附近的敌人，如果没有敌人则可以立即恢复探索
        bool has_nearby_enemies = false;
        if(is_leader) {
            for(const auto &e : info.enemy_armies) {
                int dist = abs(e.BlockDR - ship.BlockDR) + abs(e.BlockUR - ship.BlockUR);
                if(dist <= 25) { has_nearby_enemies = true; break; }
            }
            for(const auto &e : info.enemy_buildings) {
                int dist = abs(e.BlockDR - ship.BlockDR) + abs(e.BlockUR - ship.BlockUR);
                if(dist <= 25) { has_nearby_enemies = true; break; }
            }
            for(const auto &e : info.enemy_farmers) {
                int dist = abs(e.BlockDR - ship.BlockDR) + abs(e.BlockUR - ship.BlockUR);
                if(dist <= 25) { has_nearby_enemies = true; break; }
            }
        }

        bool can_explore = (info.GameFrame - last_combat_frame > 120) || !has_nearby_enemies;

        // 添加调试信息，帮助诊断探索目标计算问题
        static int last_debug_frame = -1;
        if(is_leader && info.GameFrame - last_debug_frame > 300) {
            ai->DebugText("Leader exploration status: target=(" +
                         to_string(g_ai_state.shared_exploration_target.x) + "," +
                         to_string(g_ai_state.shared_exploration_target.y) +
                         "), can_explore=" + to_string(can_explore) +
                         ", combat_frames_ago=" + to_string(info.GameFrame - last_combat_frame) +
                         ", has_nearby_enemies=" + to_string(has_nearby_enemies) +
                         ", exploration_phase=" + to_string(g_ai_state.exploration_phase) +
                         ", stuck_frames=" + to_string(stuck_frames[ship.SN]));
            last_debug_frame = info.GameFrame;
        }

        if(is_leader && g_ai_state.shared_exploration_target.x == -1 && can_explore) {
            // 使用全局阶段标志，避免阴影变量导致状态不同步
            int &exploration_phase = g_ai_state.exploration_phase; // 0: 对角探索找敌方大陆, 1: 沿敌方海岸线探索
            static int diagonal_progress = 0;  // 对角探索进度
            static Point last_land_found = {-1, -1}; // 发现的敌方陆地位置

            // 检测重置信号并重置静态变量
            if(g_ai_state.total_exploration_frames == -1) {
                diagonal_progress = 0;
                last_land_found = {-1, -1};
                g_ai_state.total_exploration_frames = 0; // 清除重置信号
                ai->DebugText("Reset static exploration variables after stuck detection");
            }
            
            Point new_target = {-1, -1};
            static Point enemy_diagonal = {-1, -1}; // 敌方对角位置
            
            if(exploration_phase == 0) {
                // 阶段0：找到我方大陆的对角，直接朝敌方对角前进
                static bool diagonal_determined = false;
                
                if(!diagonal_determined) {
                    // 检查8个候选点：4个象限中心点 + 4个边中点
                    Point candidate_points[] = {
                        {30, 30},   // 左上块中点
                        {90, 30},   // 右上块中点
                        {90, 90},   // 右下块中点
                        {30, 90},   // 左下块中点
                        {60, 30},   // 上边中点
                        {90, 60},   // 右边中点
                        {60, 90},   // 下边中点
                        {30, 60}    // 左边中点
                    };

                    // 对应的敌方目标（对角位置）
                    Point enemy_targets[] = {
                        {90, 90},   // 左上 -> 右下
                        {30, 90},   // 右上 -> 左下
                        {30, 30},   // 右下 -> 左上
                        {90, 30},   // 左下 -> 右上
                        {60, 90},   // 上边 -> 下边
                        {30, 60},   // 右边 -> 左边
                        {60, 30},   // 下边 -> 上边
                        {90, 60}    // 左边 -> 右边
                    };

                    vector<Point> valid_enemy_targets;

                    // 检测所有8个候选点，收集所有有效的敌方目标
                    for(int i = 0; i < 8; i++) {
                        Point test_pos = candidate_points[i];
                        if(test_pos.x >= 0 && test_pos.x < 128 && test_pos.y >= 0 && test_pos.y < 128) {
                            int tile = (*info.theMap)[test_pos.x][test_pos.y].type;
                            if(tile == MAPPATTERN_GRASS || tile == MAPPATTERN_DESERT) {
                                // 找到我方大陆位置，添加对应的敌方探索点
                                valid_enemy_targets.push_back(enemy_targets[i]);
                                string point_name[] = {"left-top", "right-top", "right-bottom", "left-bottom",
                                                     "top-edge", "right-edge", "bottom-edge", "left-edge"};
                                ai->DebugText("My land found at " + point_name[i] + " (" +
                                             to_string(test_pos.x) + "," + to_string(test_pos.y) +
                                             "), adding enemy target: (" + to_string(enemy_targets[i].x) + "," + to_string(enemy_targets[i].y) + ")");
                            }
                        }
                    }

                    // 备用逻辑：如果8个候选点都没找到我方陆地，使用市镇中心对角
                    if(valid_enemy_targets.empty()) {
                        const tagBuilding* tc = getTownCenter(info);
                        if(tc) {
                            // 计算市镇中心的对角位置
                            int tc_x = tc->BlockDR;
                            int tc_y = tc->BlockUR;
                            Point tc_diagonal = {120 - tc_x, 120 - tc_y}; // 简单的对角计算
                            valid_enemy_targets.push_back(tc_diagonal);
                            ai->DebugText("Using town center diagonal fallback: TC at (" +
                                         to_string(tc_x) + "," + to_string(tc_y) +
                                         "), enemy target: (" + to_string(tc_diagonal.x) + "," + to_string(tc_diagonal.y) + ")");
                        }
                    }

                    // 如果只得到一个目标，增补其余对角候选，避免反复重选同一目标
                    if(valid_enemy_targets.size() == 1) {
                        Point first = valid_enemy_targets[0];
                        vector<Point> augmented; augmented.reserve(8);
                        augmented.push_back(first);
                        for(int i = 0; i < 8; ++i) {
                            Point cand = enemy_targets[i];
                            if(!(cand.x == first.x && cand.y == first.y)) {
                                augmented.push_back(cand);
                            }
                        }
                        valid_enemy_targets.swap(augmented);
                        ai->DebugText("Augmented diagonal targets to " + to_string((int)valid_enemy_targets.size()));
                    }

                    // 存储所有有效目标到全局状态，用于后续尝试
                    if(!valid_enemy_targets.empty()) {
                        g_ai_state.symmetric_targets = valid_enemy_targets;
                        g_ai_state.current_target_index = 0;
                        enemy_diagonal = valid_enemy_targets[0]; // 先尝试第一个目标
                        g_ai_state.shared_exploration_target = enemy_diagonal;
                        diagonal_determined = true;
                        ai->DebugText("Initialized " + to_string((int)valid_enemy_targets.size()) + " diagonal targets, starting with (" +
                                     to_string(enemy_diagonal.x) + "," + to_string(enemy_diagonal.y) + ")");
                    }
                }
                
                // 直接朝敌方对角前进（以领队当前位置为起点）
                                 if(enemy_diagonal.x != -1 && diagonal_progress == 0) {
                     new_target = enemy_diagonal;
                     diagonal_progress = 1;
                     ai->DebugText("Set enemy diagonal (" + to_string(enemy_diagonal.x) + "," + to_string(enemy_diagonal.y) + ") as fleet exploration target");
                 }
                
                // 对角探索完成，切换到沿岸探索（增加探索次数确保找到敌方大陆）
                if(diagonal_progress >= 8 || g_ai_state.enemy_land_found) {
                    exploration_phase = 1;
                    diagonal_progress = 0;
                    static bool coastline_msg_sent = false;
                    if(!coastline_msg_sent) {
                        ai->DebugText("Reached enemy area, switching to coastline exploration");
                        coastline_msg_sent = true;
                    }
                    // 不重置diagonal_determined，锁定enemy_diagonal
                }
            }
            
            if(exploration_phase == 1 && new_target.x == -1) {
                // 基于敌岸的一圈“贴岸海面”单层探索：优先一圈内的海面格
                static vector<Point> coast_ring;
                static int coast_idx = 0;
                if(coast_ring.empty() && g_ai_state.enemy_land_found){
                    const Point anchor = g_ai_state.enemy_land_pos;
                    // 收集一层环上的贴岸海面（半径6-10即可），最多收集16个稀疏点
                    for(int r=6; r<=10 && (int)coast_ring.size()<16; ++r){
                        for(int i=0;i<8*r && (int)coast_ring.size()<16; ++i){
                            Point t = getSpiralPoint(anchor.x, anchor.y, i, r);
                            if(t.x<4||t.x>=124||t.y<4||t.y>=124) continue;
                            if((*info.theMap)[t.x][t.y].type != MAPPATTERN_OCEAN) continue;
                            // 距离敌方陆地1-2格（避免严格贴岸卡住）
                            int min_enemy_coast_dist = 999;
                            const int d8[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}};
                            for(int d=0; d<8; ++d){
                                for(int dist=1; dist<=3; ++dist){
                                    int nx=t.x+d8[d][0]*dist, ny=t.y+d8[d][1]*dist;
                                    if(nx<0||nx>=128||ny<0||ny>=128) continue;
                                    int tp=(*info.theMap)[nx][ny].type;
                                    if((tp==MAPPATTERN_GRASS||tp==MAPPATTERN_DESERT) && !g_ai_state.ownLand[nx][ny]){
                                        min_enemy_coast_dist = min(min_enemy_coast_dist, dist);
                                        break;
                                    }
                                }
                            }
                            if(min_enemy_coast_dist < 1 || min_enemy_coast_dist > 2) continue;
                            // 去重：与已选目标保持至少6格曼哈顿距离
                            bool too_close=false; for(const auto &q: coast_ring){ if(abs(q.x-t.x)+abs(q.y-t.y)<=6){too_close=true; break;} }
                            if(!too_close) coast_ring.push_back(t);
                        }
                    }
                    coast_idx = 0;
                    if(!coast_ring.empty()) ai->DebugText("Initialized enemy coast ring targets: " + to_string((int)coast_ring.size()));
                }
                if(!coast_ring.empty()){
                    new_target = coast_ring[coast_idx % coast_ring.size()];
                    coast_idx++;
                }
            }
            
            if(new_target.x != -1) {
                g_ai_state.shared_exploration_target = new_target;
            }
        }
                        
        // 检查是否已到达目标
        if(is_leader && g_ai_state.shared_exploration_target.x != -1) {
            int dx = abs(ship.BlockDR - g_ai_state.shared_exploration_target.x);
            int dy = abs(ship.BlockUR - g_ai_state.shared_exploration_target.y);
            int current_dist = dx + dy;
            
            // 进度型卡死检测：只要距离在缩短就不算卡住
            static Point last_leader_pos = {-1, -1};
            static int last_dist_to_target = 999;
            static int stagnate_frames = 0;
            
            bool made_progress = false;
            if(last_leader_pos.x != -1) {
                // 检查是否有实质进展（距离目标更近了）
                if(current_dist + 1 < last_dist_to_target) {
                    made_progress = true;
                    stagnate_frames = 0;
                    last_dist_to_target = current_dist;
                } else {
                    stagnate_frames++;
                }
            } else {
                made_progress = true; // 第一次记录位置
                last_dist_to_target = current_dist;
                stagnate_frames = 0;
            }
            last_leader_pos = {ship.BlockDR, ship.BlockUR};
            
            // 到达目标（或靠近）或长时间无进展
            if((dx <= 1 && dy <= 1 && made_progress) || stagnate_frames > 300) {
                if(dx <= 1 && dy <= 1) {
                    // 节流：只在目标变更时打印，避免刷屏
                    static Point last_target_change = {-1, -1};
                    if(last_target_change.x != g_ai_state.shared_exploration_target.x || 
                       last_target_change.y != g_ai_state.shared_exploration_target.y) {
                        ai->DebugText("Leader reached target, calculating next");
                        last_target_change = g_ai_state.shared_exploration_target;
                    }

                    // 如果是对角探索阶段，尝试下一个目标
                    if(g_ai_state.exploration_phase == 0) {
                        // 检查是否还有未尝试的对角目标
                        if(g_ai_state.current_target_index + 1 < (int)g_ai_state.symmetric_targets.size()) {
                            // 尝试下一个对角目标
                            g_ai_state.current_target_index++;
                            Point next_target = g_ai_state.symmetric_targets[g_ai_state.current_target_index];
                            g_ai_state.shared_exploration_target = next_target;
                            ai->DebugText("Trying next diagonal target (" + to_string(next_target.x) + "," + to_string(next_target.y) +
                                         "), index: " + to_string(g_ai_state.current_target_index));
                        } else {
                            // 所有对角目标都尝试过了：切换到沿岸探索阶段
                            g_ai_state.shared_exploration_target = {-1, -1};
                            g_ai_state.exploration_phase = 1; // 进入沿岸探索
                            ai->DebugText("All diagonal targets exhausted, switching to coastline exploration");
                        }
                    } else {
                        // 其他阶段正常重置
                        g_ai_state.shared_exploration_target = {-1, -1};
                    }
                } else {
                    // 卡住：保持方向继续延长探索，避免“回头”重置导致永远到不了敌岸
                    Point current_pos = {ship.BlockDR, ship.BlockUR};
                    Point current_target = g_ai_state.shared_exploration_target;
                    const tagBuilding* tc = getTownCenter(info);
                    Point my_center = tc ? Point{tc->BlockDR, tc->BlockUR} : Point{64, 64};
                    int dir_x = current_target.x - my_center.x;
                    int dir_y = current_target.y - my_center.y;
                    if(dir_x != 0) dir_x = (dir_x > 0) ? 1 : -1;
                    if(dir_y != 0) dir_y = (dir_y > 0) ? 1 : -1;
                    int extend_distance = 70 + (info.GameFrame % 30); // 增加卡住时的延伸距离
                    Point extended = { current_pos.x + dir_x * extend_distance,
                                       current_pos.y + dir_y * extend_distance };
                    extended.x = max(5, min(122, extended.x));
                    extended.y = max(5, min(122, extended.y));
                    g_ai_state.shared_exploration_target = extended;
                    ai->DebugText("Leader stagnated " + to_string(stagnate_frames) + ", extending toward (" + to_string(extended.x) + "," + to_string(extended.y) + ")");
                }
                stagnate_frames = 0;
                last_dist_to_target = 999;
            }
        }
        
        // 编队协同逻辑：所有船一起行动、攻击同一敌人
        if(g_ai_state.fleet_guard_mode && g_ai_state.fleet_rally.x != -1){
            // 守备模式：所有已出发战船驻扎于据点前海，遇敌即攻，离开后回归
            int rx = g_ai_state.fleet_rally.x, ry = g_ai_state.fleet_rally.y;
            int d2r = abs(ship.BlockDR - rx) + abs(ship.BlockUR - ry);
            if(d2r > 3){ ai->HumanMove(ship.SN, rx*BLOCKSIDELENGTH, ry*BLOCKSIDELENGTH); continue; }
            // 守备：如无共享目标则静待（下方统一敌人侦测会处理攻击），不推进探索
        } else if(g_ai_state.shared_exploration_target.x != -1) {
            int target_x = g_ai_state.shared_exploration_target.x;
            int target_y = g_ai_state.shared_exploration_target.y;

            // 编队保持：非队长更紧凑地跟随队长，尽量停在靠近领队的海面安全点
            if(!is_leader && current_leader_sn != -1 && leader_pos_cache.x != -1) {
                int dx = abs(ship.BlockDR - leader_pos_cache.x);
                int dy = abs(ship.BlockUR - leader_pos_cache.y);
                if(dx + dy > 4) { // 收紧编距，减少掉队
                    int follow_x = leader_pos_cache.x, follow_y = leader_pos_cache.y;
                    bool found_pos = false;
                    // 先找 1~2 格内安全海面
                    for(int r=1;r<=2 && !found_pos;++r){
                        for(int i=0;i<8*r && !found_pos;++i){
                            Point t = getSpiralPoint(leader_pos_cache.x, leader_pos_cache.y, i, r);
                            if(t.x>=0&&t.x<128&&t.y>=0&&t.y<128 && (*info.theMap)[t.x][t.y].type==MAPPATTERN_OCEAN){
                                bool occupied = false;
                                for(const auto &other : info.armies) {
                                    if(other.Sort == AT_SHIP && other.SN != ship.SN &&
                                       abs(other.BlockDR - t.x) + abs(other.BlockUR - t.y) <= 1) { occupied = true; break; }
                                }
                                if(!occupied) { follow_x=t.x; follow_y=t.y; found_pos = true; }
                            }
                        }
                    }
                    // 若太近找不到，则退回 3~4 格环
                    for(int r=3;r<=4 && !found_pos;++r){
                        for(int i=0;i<8*r && !found_pos;++i){
                            Point t = getSpiralPoint(leader_pos_cache.x, leader_pos_cache.y, i, r);
                            if(t.x>=0&&t.x<128&&t.y>=0&&t.y<128 && (*info.theMap)[t.x][t.y].type==MAPPATTERN_OCEAN){
                                bool occupied = false;
                                for(const auto &other : info.armies) {
                                    if(other.Sort == AT_SHIP && other.SN != ship.SN &&
                                       abs(other.BlockDR - t.x) + abs(other.BlockUR - t.y) <= 1) { occupied = true; break; }
                                }
                                if(!occupied) { follow_x=t.x; follow_y=t.y; found_pos = true; }
                            }
                        }
                    }
                    ai->HumanMove(ship.SN, follow_x * BLOCKSIDELENGTH, follow_y * BLOCKSIDELENGTH);
                    continue;
                }
            }

            // 只有当编队中至少一半船已靠近队长时推进；否则继续等待跟随
            int num_close = 0, num_total = 0;
            if(is_leader){
                for(const auto &other : info.armies){
                    if(other.Sort == AT_SHIP && g_ai_state.launched_warship_SNs.count(other.SN) > 0){
                        ++num_total;
                        int d = abs(other.BlockDR - ship.BlockDR) + abs(other.BlockUR - ship.BlockUR);
                        if(d <= 3) ++num_close;
                    }
                }
            }

            // 简化领队推进条件：领队始终可以推进，减少等待时间
            bool leader_may_push = true;

            // 验证目标（简化）
            bool target_ok = (target_x >= 0 && target_x < 128 && target_y >= 0 && target_y < 128);

            // 修复：如果没有有效目标且是领队，强制触发目标重新计算
            if(!target_ok && is_leader) {
                g_ai_state.shared_exploration_target = {-1, -1};
                ai->DebugText("No valid target, forcing exploration target recalculation");
                continue; // 下一帧重新计算目标
            }

            if(target_ok) {
                // 统一敌人侦测与攻击（与原逻辑相同）
                static int shared_enemy_target = -1;
                static int enemy_target_frame = -1;

                if(is_leader) {
                    int nearest_enemy_sn = -1;
                    int nearest_enemy_dist = 999;
                    int fleet_center_x = 0, fleet_center_y = 0, fleet_count = 0;
                    for(const auto &other : info.armies) {
                        if(other.Sort == AT_SHIP && g_ai_state.launched_warship_SNs.count(other.SN) > 0) {
                            fleet_center_x += other.BlockDR;
                            fleet_center_y += other.BlockUR;
                            fleet_count++;
                        }
                    }
                    if(fleet_count > 0) { fleet_center_x/=fleet_count; fleet_center_y/=fleet_count; }
                    for(const auto &e:info.enemy_armies){
                        int dist=abs(e.BlockDR-fleet_center_x)+abs(e.BlockUR-fleet_center_y);
                        if(dist<nearest_enemy_dist && dist<=20){nearest_enemy_sn=e.SN;nearest_enemy_dist=dist;}
                    }
                    for(const auto &e:info.enemy_buildings){
                        int dist=abs(e.BlockDR-fleet_center_x)+abs(e.BlockUR-fleet_center_y);
                        if(dist<nearest_enemy_dist && dist<=20){nearest_enemy_sn=e.SN;nearest_enemy_dist=dist;}
                    }
                    for(const auto &e:info.enemy_farmers){
                        int dist=abs(e.BlockDR-fleet_center_x)+abs(e.BlockUR-fleet_center_y);
                        if(dist<nearest_enemy_dist && dist<=20){nearest_enemy_sn=e.SN;nearest_enemy_dist=dist;}
                    }
                    if(nearest_enemy_sn!=-1){shared_enemy_target=nearest_enemy_sn;enemy_target_frame=info.GameFrame;}
                    else if(info.GameFrame-enemy_target_frame>60){shared_enemy_target=-1;}
                }

                if(shared_enemy_target!=-1){
                    // 只有当战船不在攻击状态，或者攻击目标不是当前共享目标时，才发送攻击命令
                    bool should_attack = false;
                    if(ship.NowState != HUMAN_STATE_ATTACKING) {
                        should_attack = true;
                    } else if(ship.WorkObjectSN != shared_enemy_target) {
                        should_attack = true;
                    }

                    if(should_attack) {
                        ai->HumanAction(ship.SN, shared_enemy_target);
                    }
                } else {
                    if(leader_may_push){
                        // 按船节流 + 目标若为陆地则就近找海面
                        static std::unordered_map<int,int> lastMoveFrame;
                        int last = (lastMoveFrame.count(ship.SN)? lastMoveFrame[ship.SN] : -9999);
                        if(info.GameFrame - last > 15){ // 略放缓，减少抖动与掉队
                            int dest_x = target_x, dest_y = target_y;
                            if(dest_x>=0 && dest_x<128 && dest_y>=0 && dest_y<128){
                                // 简化的目标验证：只在目标不是海洋时寻找附近海洋
                                if((*info.theMap)[dest_x][dest_y].type != MAPPATTERN_OCEAN){
                                    bool found=false;
                                    for(int r=1; r<=8 && !found; ++r){
                                        for(int i=0; i<8*r && !found; ++i){
                                            Point t = getSpiralPoint(target_x, target_y, i, r);
                                            if(t.x>=0 && t.x<128 && t.y>=0 && t.y<128 && (*info.theMap)[t.x][t.y].type==MAPPATTERN_OCEAN){
                                                dest_x=t.x; dest_y=t.y; found=true;
                                            }
                                        }
                                    }
                                }

                                int mv_ret = ai->HumanMove(ship.SN, dest_x * BLOCKSIDELENGTH, dest_y * BLOCKSIDELENGTH);
                                if(is_leader) {
                                    if(mv_ret <= 0) {
                                        stuck_frames[ship.SN] += 20; // 移动失败时增加stuck累积
                                        ai->DebugText("Leader move FAILED to (" + to_string(dest_x) + "," + to_string(dest_y) +
                                                    "), stuck_frames now: " + to_string(stuck_frames[ship.SN]));
                                    } else {
                                        ai->DebugText("Leader moving to (" + to_string(dest_x) + "," + to_string(dest_y) + ")");
                                    }
                                }
                            }
                            lastMoveFrame[ship.SN] = info.GameFrame;
                        }
                    } else if(!is_leader && leader_pos_cache.x != -1){
                        // 等待队长，不推进；让队员靠近领队，减少散开
                        if(abs(ship.BlockDR - leader_pos_cache.x) + abs(ship.BlockUR - leader_pos_cache.y) > 2){
                            ai->HumanMove(ship.SN, leader_pos_cache.x * BLOCKSIDELENGTH, leader_pos_cache.y * BLOCKSIDELENGTH);
                        }
                    }
                }
            }
        }
    }

    // ------------------------------------------------------------------
    // 7.3 科技升级：遍历所有已完工且空闲建筑，自动研究可用科技
    // ------------------------------------------------------------------
    {
        // lambda 尝试研究
        auto tryResearch = [&](const tagBuilding &bd, int action, int foodCost, int woodCost, int stoneCost){
            if(g_ai_state.finished_techs.count(action)) return; // 已完成
            if(bd.Project != 0 || bd.Percent < 100) return; // 确保建筑空闲完工
            if(temp_meat < foodCost || temp_wood < woodCost || temp_stone < stoneCost) return; // 资源不足
            int id = ai->BuildingAction(bd.SN, action);
            if(id > 0){
                // 记录消耗与完成标志
                temp_meat  -= foodCost;
                temp_wood  -= woodCost;
                temp_stone -= stoneCost;
                g_ai_state.finished_techs.insert(action);
                ai->DebugText("Research tech action " + to_string(action));
            }
        };

        for(const auto &pairBd : g_ai_state.buildings){
            const tagBuilding &bd = pairBd.second;
            switch(bd.Type){
                case BUILDING_MARKET:
                    tryResearch(bd, BUILDING_MARKET_WOOD_UPGRADE,  BUILDING_MARKET_WOOD_UPGRADE_FOOD,  BUILDING_MARKET_WOOD_UPGRADE_WOOD, 0);
                    tryResearch(bd, BUILDING_MARKET_STONE_UPGRADE, BUILDING_MARKET_STONE_UPGRADE_FOOD, 0, BUILDING_MARKET_STONE_UPGRADE_STONE);
                    tryResearch(bd, BUILDING_MARKET_FARM_UPGRADE,  BUILDING_MARKET_FARM_UPGRADE_FOOD,  BUILDING_MARKET_FARM_UPGRADE_WOOD, 0);
                    break;
                case BUILDING_STOCK:
                    tryResearch(bd, BUILDING_STOCK_UPGRADE_USETOOL,        BUILDING_STOCK_UPGRADE_USETOOL_FOOD, 0, 0);
                    tryResearch(bd, BUILDING_STOCK_UPGRADE_DEFENSE_INFANTRY,BUILDING_STOCK_UPGRADE_DEFENSE_INFANTRY_FOOD, 0, 0);
                    tryResearch(bd, BUILDING_STOCK_UPGRADE_DEFENSE_ARCHER,  BUILDING_STOCK_UPGRADE_DEFENSE_ARCHER_FOOD, 0, 0);
                    tryResearch(bd, BUILDING_STOCK_UPGRADE_DEFENSE_RIDER,   BUILDING_STOCK_UPGRADE_DEFENSE_RIDER_FOOD, 0, 0);
                    break;
                case BUILDING_GRANARY:
                    tryResearch(bd, BUILDING_GRANARY_ARROWTOWER, BUILDING_GRANARY_ARROWTOWER_FOOD, 0, 0);
                    break;
                case BUILDING_ARMYCAMP:
                    tryResearch(bd, BUILDING_ARMYCAMP_UPGRADE_CLUBMAN, BUILDING_ARMYCAMP_UPGRADE_CLUBMAN_FOOD, 0, 0);
                    break;
                default:
                    break;
            }
        }
    }

    // ------------------------------------------------------------------
    // 7.4 运输船装载与出发逻辑
    // ------------------------------------------------------------------
    // 识别并记录运输船 SN
    if(g_ai_state.transport_sn == -1){
        for(const auto &fp : info.farmers){
            if(fp.FarmerSort == FARMER_SORT_WOOD_BOAT){
                g_ai_state.transport_sn = fp.SN;
                ai->DebugText("Transport ship ready, SN=" + to_string(fp.SN));
                break;
            }
        }
    }
    // --- 装载村民到运输船（修复版） ---
    if(g_ai_state.transport_sn != -1){
        // 获取运输船当前信息
        tagFarmer *transportPtr = nullptr;
        auto itShip = g_ai_state.farmers.find(g_ai_state.transport_sn);
        if(itShip != g_ai_state.farmers.end()) transportPtr = &(itShip->second);

        if(transportPtr){
            int currentLoad = transportPtr->Resource; // 对于运输船，该字段表示已载人数
            
            // 添加移动冷却机制，避免频繁移动
            static int last_move_frame = -1;
            static Point last_target = {-1, -1};
            int current_frame = info.GameFrame;
            
            // 检查是否有空闲农民在附近（扩大搜索范围）
            bool has_nearby_farmers = false;
            int nearest_farmer_dist = 1000;
            for(int farmer_sn : g_ai_state.idleFarmerSNs) {
                const tagFarmer &farmer = g_ai_state.farmers[farmer_sn];
                int dist2 = (farmer.BlockDR - transportPtr->BlockDR) * (farmer.BlockDR - transportPtr->BlockDR) + 
                           (farmer.BlockUR - transportPtr->BlockUR) * (farmer.BlockUR - transportPtr->BlockUR);
                if(dist2 <= 100) { // 距离小于10格
                    has_nearby_farmers = true;
                    nearest_farmer_dist = min(nearest_farmer_dist, (int)sqrt(dist2));
                    break;
                }
            }
            
            // 如果没有附近农民，检查是否需要移动到岸边（添加冷却时间）
            if(!has_nearby_farmers && currentLoad < 4 && 
               !g_ai_state.transport_anchored &&
               (current_frame - last_move_frame > 150)) { // 150帧冷却时间，约4秒
                
                // 寻找平坦连续的岸边位置 - 避免尖角和复杂地形
                Point best_shore_pos = {-1, -1};
                bool found_shore = false;
                int best_coastline_score = -1;

                // 限流打印，避免反复刷屏
                static int last_anchor_search_debug_frame = -9999;
                if(current_frame - last_anchor_search_debug_frame > 150){
                ai->DebugText("Searching for smooth, continuous coastline for transport anchoring...");
                    last_anchor_search_debug_frame = current_frame;
                }

                // 寻找开阔平坦的海岸线位置，避免被障碍物包围的小海湾和尖角
                const tagBuilding* tc = getTownCenter(info);
                if(tc && !g_ai_state.idleFarmerSNs.empty()) {
                    // 尝试在市镇中心附近的海岸寻找位置
                    for(int r = 5; r <= 25 && !found_shore; ++r) {
                        for(int i = 0; i < 8 * r && !found_shore; ++i) {
                            Point test_pos = getSpiralPoint(tc->BlockDR, tc->BlockUR, i, r);
                            if(test_pos.x >= 0 && test_pos.x < 128 && test_pos.y >= 0 && test_pos.y < 128 &&
                               (*info.theMap)[test_pos.x][test_pos.y].type == MAPPATTERN_OCEAN) {
                                // 仅检查正交邻接陆地，更贴近登船判定
                                int orth_land_adjacent = 0;
                                const int dirs4[4][2] = {{0,-1},{1,0},{0,1},{-1,0}};
                                for(int d=0; d<4; ++d){
                                    int nx = test_pos.x + dirs4[d][0];
                                    int ny = test_pos.y + dirs4[d][1];
                                    if(nx>=0 && nx<128 && ny>=0 && ny<128){
                                        int t = (*info.theMap)[nx][ny].type;
                                        if((t == MAPPATTERN_GRASS || t == MAPPATTERN_DESERT)){
                                            orth_land_adjacent++;
                                        }
                                    }
                                }
                                int coastline_score = (orth_land_adjacent > 0) ? 1 : -1000;
                                if(coastline_score > best_coastline_score){
                                        best_coastline_score = coastline_score;
                                        best_shore_pos = test_pos;
                                }
                            }
                        }
                    }
                }

                // 如果找到了合适的位置（即使不是最优的），使用它
                if(best_coastline_score > 0 && !found_shore) {
                    found_shore = true;
                    ai->DebugText("Using coastline (orth-adjacent) with score: " + to_string(best_coastline_score));
                }

                // 如果在市镇中心附近找不到，以运输船当前位置为中心扩大搜索
                if(!found_shore) {
                    for(int r = 1; r <= 20 && !found_shore; ++r) {
                        for(int i = 0; i < 8 * r && !found_shore; ++i) {
                            Point move_pos = getSpiralPoint(transportPtr->BlockDR, transportPtr->BlockUR, i, r);
                            if(move_pos.x >= 0 && move_pos.x < 128 && move_pos.y >= 0 && move_pos.y < 128 &&
                               (*info.theMap)[move_pos.x][move_pos.y].type == MAPPATTERN_OCEAN) {

                                // 降低要求但仍需正交邻接陆地
                                bool orth_ok = false;
                                const int dirs4_fb[4][2] = {{0,-1},{1,0},{0,1},{-1,0}};
                                for(int d=0; d<4 && !orth_ok; ++d){
                                    int nx = move_pos.x + dirs4_fb[d][0];
                                    int ny = move_pos.y + dirs4_fb[d][1];
                                    if(nx>=0 && nx<128 && ny>=0 && ny<128){
                                        int t = (*info.theMap)[nx][ny].type;
                                        if((t==MAPPATTERN_GRASS || t==MAPPATTERN_DESERT) && g_ai_state.grid[nx][ny]==0){
                                            orth_ok = true;
                                        }
                                    }
                                }
                                if(orth_ok){
                                    best_shore_pos = move_pos;
                                    found_shore = true;
                                }
                            }
                        }
                    }
                }
                
                // 找到合适的岸边位置后，直接锚定在该海面格中心；并记录一个正交相邻的陆地格作为集合点
                if(found_shore && !g_ai_state.transport_anchored) {
                    g_ai_state.prev_transport_shore_pos = g_ai_state.transport_shore_pos;
                    g_ai_state.transport_shore_pos = best_shore_pos; // 记住固定靠岸点（海面格）

                    // 计算一个正交相邻的陆地格，作为引导农民的集合点
                    Point rally_land = {-1, -1};
                    const int dirs4[4][2] = {{0,-1},{1,0},{0,1},{-1,0}};
                    for(int d=0; d<4; ++d){
                        int nx = best_shore_pos.x + dirs4[d][0];
                        int ny = best_shore_pos.y + dirs4[d][1];
                        if(nx>=0 && nx<128 && ny>=0 && ny<128){
                            int t = (*info.theMap)[nx][ny].type;
                            if((t==MAPPATTERN_GRASS || t==MAPPATTERN_DESERT) && g_ai_state.grid[nx][ny]==0){
                                rally_land = {nx, ny};
                                    break;
                                }
                            }
                        }
                    // 记录集合点（可能仍为{-1,-1}，后续代码需判空）
                    g_ai_state.transport_rally_land = rally_land;

                    // 将运输船移动到海面格中心（不做半格偏移）
                    // 0.5 格偏移，贴近格中心有利于触发靠岸/上下船判定
                    double final_x = (best_shore_pos.x + 0.5) * BLOCKSIDELENGTH;
                    double final_y = (best_shore_pos.y + 0.5) * BLOCKSIDELENGTH;
                    ai->HumanMove(g_ai_state.transport_sn, final_x, final_y);

                    static bool debug_printed = false;
                    if(!debug_printed) {
                        ai->DebugText("Transport anchored at ocean (" + to_string(best_shore_pos.x) + "," +
                                     to_string(best_shore_pos.y) + ")" +
                                     (rally_land.x!=-1? (", rally land ("+to_string(rally_land.x)+","+to_string(rally_land.y)+")") : ", no rally land"));
                        debug_printed = true;
                    }

                    last_move_frame = current_frame;
                    last_target = g_ai_state.transport_shore_pos;
                    g_ai_state.transport_anchored = true; // 到岸即锚定，不再移动
                }
                // 没找到岸边则等待，找到后保持停靠，不再主动移动
                if(!found_shore){
                    static int last_no_shore_debug = -1;
                    if(info.GameFrame - last_no_shore_debug > 300) {
                        ai->DebugText("No suitable shore position found, transport waiting... (idle farmers: " +
                                     to_string(g_ai_state.idleFarmerSNs.size()) + ")");
                        last_no_shore_debug = info.GameFrame;
                    }
                    last_move_frame = current_frame;
                }
            }
            
            // 简化的运输船征兵和召唤逻辑
            // transport_squad 现在在全局状态中定义

            // 调试信息
            static int last_transport_debug_frame = -1;
            if(info.GameFrame - last_transport_debug_frame > 300) {
                ai->DebugText("Transport status: anchored=" + to_string(g_ai_state.transport_anchored) +
                             ", load=" + to_string(currentLoad) +
                             ", squad_size=" + to_string(g_ai_state.transport_squad.size()) +
                             ", boarding_farmers=" + to_string(g_ai_state.boarding_farmers.size()) +
                             ", total_farmers=" + to_string(g_ai_state.farmers.size()));
                last_transport_debug_frame = info.GameFrame;
            }

            // 第一步：如果小队为空，选出5个农民组成小队（不需要等运输船靠岸）
            const int TRANSPORT_CAP = 5;
            if(g_ai_state.transport_squad.empty() && currentLoad < TRANSPORT_CAP) {
                // 调试：显示各个农民列表的状态
                ai->DebugText("Recruiting farmers - Lists status:");
                ai->DebugText("  Idle farmers: " + to_string(g_ai_state.idleFarmerSNs.size()));
                ai->DebugText("  Stone miners: " + to_string(g_ai_state.stoneMinerSNs.size()));
                ai->DebugText("  Hunters: " + to_string(g_ai_state.hunterSNs.size()));
                ai->DebugText("  Woodcutters: " + to_string(g_ai_state.woodcutterSNs.size()));

                // 按优先级选择4个农民：空闲->采石->打猎->伐木
                vector<int> candidates;

                // 1. 空闲农民
                for(int farmer_sn : g_ai_state.idleFarmerSNs) {
                    if(candidates.size() >= TRANSPORT_CAP) break;
                    candidates.push_back(farmer_sn);
                }

                // 2. 采石工
                if(candidates.size() < TRANSPORT_CAP) {
                    for(int farmer_sn : g_ai_state.stoneMinerSNs) {
                        if(candidates.size() >= TRANSPORT_CAP) break;
                        candidates.push_back(farmer_sn);
                    }
                }

                // 3. 猎人
                if(candidates.size() < TRANSPORT_CAP) {
                    for(int farmer_sn : g_ai_state.hunterSNs) {
                        if(candidates.size() >= TRANSPORT_CAP) break;
                        candidates.push_back(farmer_sn);
                    }
                }

                // 4. 伐木工
                if(candidates.size() < TRANSPORT_CAP) {
                    for(int farmer_sn : g_ai_state.woodcutterSNs) {
                        if(candidates.size() >= TRANSPORT_CAP) break;
                        candidates.push_back(farmer_sn);
                    }
                }

                // 组成小队并从原有列表中移除
                g_ai_state.transport_squad = candidates;
                if(!g_ai_state.transport_squad.empty()) {
                    // 从各个工作列表中移除被征召的农民
                    for(int farmer_sn : g_ai_state.transport_squad) {
                        // 从空闲农民列表中移除
                        auto it = find(g_ai_state.idleFarmerSNs.begin(), g_ai_state.idleFarmerSNs.end(), farmer_sn);
                        if(it != g_ai_state.idleFarmerSNs.end()) {
                            g_ai_state.idleFarmerSNs.erase(it);
                        }

                        // 从采石工列表中移除
                        it = find(g_ai_state.stoneMinerSNs.begin(), g_ai_state.stoneMinerSNs.end(), farmer_sn);
                        if(it != g_ai_state.stoneMinerSNs.end()) {
                            g_ai_state.stoneMinerSNs.erase(it);
                        }

                        // 从猎人列表中移除
                        it = find(g_ai_state.hunterSNs.begin(), g_ai_state.hunterSNs.end(), farmer_sn);
                        if(it != g_ai_state.hunterSNs.end()) {
                            g_ai_state.hunterSNs.erase(it);
                        }

                        // 从伐木工列表中移除
                        it = find(g_ai_state.woodcutterSNs.begin(), g_ai_state.woodcutterSNs.end(), farmer_sn);
                        if(it != g_ai_state.woodcutterSNs.end()) {
                            g_ai_state.woodcutterSNs.erase(it);
                        }
                    }

                    // 显示选择的农民SN
                    string squad_sns = "";
                    for(int i = 0; i < g_ai_state.transport_squad.size(); ++i) {
                        if(i > 0) squad_sns += ",";
                        squad_sns += to_string(g_ai_state.transport_squad[i]);
                    }
                    ai->DebugText("Transport squad formed: " + to_string(g_ai_state.transport_squad.size()) + " farmers selected [" + squad_sns + "] and removed from work lists");
                }
            }

            // 简化的上船逻辑：引导（加节流）+ 定期登船命令
            static int last_board_cmd_frame = -9999;
            static std::unordered_map<int,int> next_move_frame;       // farmerSN -> frame
            static std::unordered_map<int,int> last_board_try_frame;  // farmerSN -> frame
            if(!g_ai_state.transport_squad.empty() && g_ai_state.transport_anchored) {
                // 引导：仅在距离集合点较远，且过了冷却且最近未尝试登船时，才发送 HumanMove
                if(g_ai_state.transport_rally_land.x != -1){
                    for(int farmer_sn : g_ai_state.transport_squad){
                        auto itF = g_ai_state.farmers.find(farmer_sn);
                        if(itF == g_ai_state.farmers.end()) continue; // 可能已在船上或死亡
                        g_ai_state.boarding_farmers.insert(farmer_sn);

                        const tagFarmer &fv = itF->second;
                        int dist = abs(fv.BlockDR - g_ai_state.transport_rally_land.x) +
                                   abs(fv.BlockUR - g_ai_state.transport_rally_land.y);
                        bool near_rally = (dist <= 2);
                        bool recently_tried_board = (last_board_try_frame.count(farmer_sn) &&
                                                      info.GameFrame - last_board_try_frame[farmer_sn] < 20);
                        if(!near_rally && !recently_tried_board){
                            int allow_frame = next_move_frame.count(farmer_sn) ? next_move_frame[farmer_sn] : -9999;
                            if(info.GameFrame >= allow_frame){
                                ai->HumanMove(farmer_sn,
                                              g_ai_state.transport_rally_land.x * BLOCKSIDELENGTH,
                                              g_ai_state.transport_rally_land.y * BLOCKSIDELENGTH);
                                next_move_frame[farmer_sn] = info.GameFrame + 120; // ~3秒冷却
                            }
                        }

                        // 卡死检测：距离集合点不变或变化很小时累积，超过阈值则请求重新锚定
                        int key = farmer_sn;
                        static std::unordered_map<int,std::pair<int,Point>> last_farmer_pos; // farmerSN -> (last_frame, last_block)
                        Point curPos = {fv.BlockDR, fv.BlockUR};
                        auto &rec = last_farmer_pos[key];
                        if(rec.first > 0){
                            int delta = abs(curPos.x - rec.second.x) + abs(curPos.y - rec.second.y);
                            if(delta <= 1){
                                g_ai_state.farmer_stuck_frames[key]++;
                            } else {
                                g_ai_state.farmer_stuck_frames[key] = 0;
                            }
                        }
                        rec = {info.GameFrame, curPos};
                    }
                } else {
                    // 没有可靠集合陆地：对靠岸点背后的正交陆地做一次引导（同样带冷却）
                    for(int farmer_sn : g_ai_state.transport_squad){
                        auto itF = g_ai_state.farmers.find(farmer_sn);
                        if(itF == g_ai_state.farmers.end()) continue;
                                g_ai_state.boarding_farmers.insert(farmer_sn);

                        bool recently_tried_board = (last_board_try_frame.count(farmer_sn) &&
                                                      info.GameFrame - last_board_try_frame[farmer_sn] < 20);
                        int allow_frame = next_move_frame.count(farmer_sn) ? next_move_frame[farmer_sn] : -9999;
                        if(recently_tried_board || info.GameFrame < allow_frame) continue;

                        bool guided = false;
                        const int dirs4g[4][2] = {{0,-1},{1,0},{0,1},{-1,0}};
                        for(int d=0; d<4 && !guided; ++d){
                            int nx = g_ai_state.transport_shore_pos.x + dirs4g[d][0];
                            int ny = g_ai_state.transport_shore_pos.y + dirs4g[d][1];
                            if(nx>=0 && nx<128 && ny>=0 && ny<128){
                                int t = (*info.theMap)[nx][ny].type;
                                if(t==MAPPATTERN_GRASS || t==MAPPATTERN_DESERT){
                                    ai->HumanMove(farmer_sn, nx * BLOCKSIDELENGTH, ny * BLOCKSIDELENGTH);
                                    guided = true;
                                }
                            }
                        }
                        if(guided){ next_move_frame[farmer_sn] = info.GameFrame + 120; }
                    }
                }

                // 登船：每45帧尝试一次（略加冷却）；记录每个农民最近尝试帧，避免紧随其后再引导
                if(info.GameFrame - last_board_cmd_frame >= 45){
                    last_board_cmd_frame = info.GameFrame;
                    for(int farmer_sn : g_ai_state.transport_squad){
                        auto itF = g_ai_state.farmers.find(farmer_sn);
                        if(itF == g_ai_state.farmers.end()) continue; // 可能已在船上或死亡
                        int id = ai->HumanAction(farmer_sn, g_ai_state.transport_sn);
                        last_board_try_frame[farmer_sn] = info.GameFrame;
                        (void)id; // 安静处理
                    }
                }

                // 若多名农民长时间卡住且接近对岸尖角，触发运输船“微调重锚”
                // 条件：
                //  - 已锚定
                //  - 距离上次微调超 8 秒
                //  - 小队中至少1人 stuck>180帧，或者有未上船的人且已等待超过600帧
                if(g_ai_state.transport_anchored && info.GameFrame >= g_ai_state.next_transport_reanchor_frame){
                    int stuck_cnt = 0;
                    int not_boarded_cnt = 0;
                    for(int sn : g_ai_state.transport_squad){
                        if(g_ai_state.farmer_stuck_frames.count(sn) && g_ai_state.farmer_stuck_frames[sn] > 180){
                            stuck_cnt++;
                        }
                        // 检查是否还有人没上船（在小队中但不在船上）
                        auto itF = g_ai_state.farmers.find(sn);
                        if(itF != g_ai_state.farmers.end() && itF->second.FarmerSort != 1) {
                            not_boarded_cnt++;
                        }
                    }
                    // 放宽条件：至少1人卡住，或者有人没上船且等待时间过长
                    bool should_reanchor = (stuck_cnt >= 1) ||
                                          (not_boarded_cnt > 0 && info.GameFrame - last_board_cmd_frame > 600);
                    if(should_reanchor){
                        // 以当前锚点为中心，半径3~8在海面上寻找新海面格，使其四邻陆地中距离任一农民最近
                        Point best = {-1,-1};
                        int best_score = 99999;
                        for(int r=3; r<=8; ++r){
                            int pts = 8*r;
                            for(int i=0;i<pts;++i){
                                Point t = getSpiralPoint(g_ai_state.transport_shore_pos.x, g_ai_state.transport_shore_pos.y, i, r);
                                if(t.x<0||t.x>=128||t.y<0||t.y>=128) continue;
                                if((*info.theMap)[t.x][t.y].type != MAPPATTERN_OCEAN) continue;
                                // 必须正交邻接陆地
                                bool has_land=false; Point land={-1,-1};
                                const int d4[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
                                for(int d=0; d<4; ++d){
                                    int nx=t.x+d4[d][0], ny=t.y+d4[d][1];
                                    if(nx<0||nx>=128||ny<0||ny>=128) continue;
                                    int tt=(*info.theMap)[nx][ny].type;
                                    if(tt==MAPPATTERN_GRASS || tt==MAPPATTERN_DESERT){ has_land=true; land={nx,ny}; break; }
                                }
                                if(!has_land) continue;
                                // 评分：到小队成员的最近距离
                                int minDist = 99999;
                                for(int sn : g_ai_state.transport_squad){
                                    auto itF = g_ai_state.farmers.find(sn); if(itF==g_ai_state.farmers.end()) continue;
                                    int d = abs(itF->second.BlockDR - land.x) + abs(itF->second.BlockUR - land.y);
                                    if(d<minDist) minDist=d;
                                }
                                if(minDist < best_score){ best_score=minDist; best=t; }
                            }
                        }
                        if(best.x!=-1){
                            // 移动运输船到新的锚点，并更新集合点
                            // 若新锚点与上一个锚点相同，扩大半径并放宽到含对角陆地
                            if(best.x == g_ai_state.prev_transport_shore_pos.x && best.y == g_ai_state.prev_transport_shore_pos.y){
                                for(int r=6; r<=12 && best.x==-1; ++r){
                                    int pts=8*r; for(int i=0;i<pts;++i){ Point t=getSpiralPoint(g_ai_state.transport_shore_pos.x,g_ai_state.transport_shore_pos.y,i,r); if(t.x<0||t.x>=128||t.y<0||t.y>=128) continue; if((*info.theMap)[t.x][t.y].type!=MAPPATTERN_OCEAN) continue; bool ok=false; for(int dx=-1;dx<=1&&!ok;++dx){ for(int dy=-1;dy<=1&&!ok;++dy){ if(dx==0&&dy==0) continue; int nx=t.x+dx,ny=t.y+dy; if(nx<0||nx>=128||ny<0||ny>=128) continue; int tt=(*info.theMap)[nx][ny].type; if(tt==MAPPATTERN_GRASS||tt==MAPPATTERN_DESERT) ok=true; }} if(ok){ best=t; break; } }
                                }
                            }
                            g_ai_state.transport_shore_pos = best;
                            ai->HumanMove(g_ai_state.transport_sn, (best.x+0.5)*BLOCKSIDELENGTH, (best.y+0.5)*BLOCKSIDELENGTH);
                            // 更新集合陆地
                            Point rally={-1,-1}; const int d4[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
                            for(int d=0; d<4; ++d){ int nx=best.x+d4[d][0], ny=best.y+d4[d][1]; if(nx<0||nx>=128||ny<0||ny>=128) continue; int tt=(*info.theMap)[nx][ny].type; if(tt==MAPPATTERN_GRASS||tt==MAPPATTERN_DESERT){ rally={nx,ny}; break; } }
                            g_ai_state.transport_rally_land = rally;
                            // 冷却 8 秒
                            g_ai_state.next_transport_reanchor_frame = info.GameFrame + 8*60;
                            // 清零卡住计数
                            for(int sn : g_ai_state.transport_squad){ g_ai_state.farmer_stuck_frames[sn]=0; }
                        }
                    }
                }
            }



            // 当装载人数达到5并且尚未出发时，指挥运输船前往“靠海陆地/海面”并确保靠岸卸载
            if(currentLoad >= TRANSPORT_CAP && g_ai_state.enemy_land_found && !g_ai_state.transport_dispatched){
                // 找到敌岸附近的“靠海陆地”（四邻含海洋，且尽量不在己方 ownLand 中）
                Point landing_land = findCoastalLandNear(g_ai_state.enemy_land_pos, info, /*prefer_enemy_land*/true);
                if(landing_land.x == -1){
                    // 退化：直接用 enemy_land_pos
                    landing_land = g_ai_state.enemy_land_pos;
                }
                // 按文档：对运输船执行 HumanMove 到“靠海陆地”可触发自动下船
                Point dest = landing_land;
                ai->HumanMove(g_ai_state.transport_sn, (dest.x + 0.5) * BLOCKSIDELENGTH, (dest.y + 0.5) * BLOCKSIDELENGTH);
                g_ai_state.transport_dispatched = true;
                g_ai_state.transport_anchored = false; // 起航解除锚定标志
                ai->DebugText(string("Transport sailing to coastal land: (") + to_string(dest.x) + "," + to_string(dest.y) + ")");
            }

            // 出航后靠岸“轻推”以确保触发自动卸载（增加到达确认机制）
            if(g_ai_state.transport_dispatched && currentLoad > 0){
                static int last_unload_nudge_frame = -9999;
                static Point last_target = {-1, -1};
                static int target_arrival_frame = -1;

                // 检查运输船是否到达当前目标
                bool arrived_at_target = false;
                if(last_target.x != -1 && transportPtr) {
                    int dist_to_target = abs(transportPtr->BlockDR - last_target.x) + abs(transportPtr->BlockUR - last_target.y);
                    if(dist_to_target <= 2) { // 到达目标附近2格内
                        if(target_arrival_frame == -1) {
                            target_arrival_frame = info.GameFrame; // 记录到达时间
                            ai->DebugText("Transport arrived at target (" + to_string(last_target.x) + "," + to_string(last_target.y) + "), waiting for unload");
                            // 关键：一旦到达，重置微调计时，至少等待 required_interval 后再尝试移动
                            last_unload_nudge_frame = info.GameFrame;
                        }
                        arrived_at_target = true;
                    } else {
                        target_arrival_frame = -1; // 重置到达时间
                    }
                }

                // 增加移动间隔：到达目标后等待120帧（2秒），未到达时等待180帧（3秒）
                int required_interval = arrived_at_target ? 120 : 180;
                if(arrived_at_target && target_arrival_frame != -1) {
                    required_interval = max(120, info.GameFrame - target_arrival_frame); // 到达后至少等待2秒
                }

                if(info.GameFrame - last_unload_nudge_frame >= required_interval){
                    bool handled_unload_attempt = false;
                    // 优先微调：若已到达目标附近且仍未卸载，先尝试将运输船移动到目标陆地的正交相邻海面格
                    if(arrived_at_target && currentLoad > 0 && last_target.x != -1){
                        bool moved_to_ocean = false;
                        const int d4o[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
                        for(int d=0; d<4 && !moved_to_ocean; ++d){
                            int ox = last_target.x + d4o[d][0];
                            int oy = last_target.y + d4o[d][1];
                            if(ox<0||ox>=128||oy<0||oy>=128) continue;
                            if((*info.theMap)[ox][oy].type==MAPPATTERN_OCEAN){
                                ai->HumanMove(g_ai_state.transport_sn, (ox + 0.5) * BLOCKSIDELENGTH, (oy + 0.5) * BLOCKSIDELENGTH);
                                moved_to_ocean = true;
                            }
                        }
                        if(moved_to_ocean){
                            last_unload_nudge_frame = info.GameFrame;
                            // 不改变 last_target，让下一轮继续以同一登陆点重试
                            handled_unload_attempt = true;
                        }
                    }
                    if(!handled_unload_attempt){
                        // 若还未准备好候选，生成若干不重复的“靠海陆地”候选点（正交邻海，且未被占用）
                        if(g_ai_state.transport_landing_candidates.empty()){
                            vector<Point> cands;
                            Point base = (g_ai_state.enemy_land_pos.x!=-1)? g_ai_state.enemy_land_pos : Point{64,64};
                            for(int r=3; r<=10 && (int)cands.size()<8; ++r){
                                int pts=8*r; for(int i=0;i<pts && (int)cands.size()<8; ++i){
                                    Point p = getSpiralPoint(base.x, base.y, i, r);
                                    if(p.x<0||p.x>=128||p.y<0||p.y>=128) continue;
                                    int t = (*info.theMap)[p.x][p.y].type;
                                    if(!(t==MAPPATTERN_GRASS || t==MAPPATTERN_DESERT)) continue;
                                    if(g_ai_state.ownLand[p.x][p.y]) continue; // 敌岸优先
                                    if(g_ai_state.grid[p.x][p.y] == 1) continue; // 登陆点不可被占用
                                    // 跳过历史已尝试的登陆点
                                    int h = (p.x<<8) | p.y; if(g_ai_state.tried_landing_hash.count(h)) continue;
                                    // 正交邻接海洋，避免卡拐角
                                    bool orth_ocean=false; const int d4[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
                                    for(int d=0; d<4 && !orth_ocean; ++d){ int nx=p.x+d4[d][0], ny=p.y+d4[d][1]; if(nx<0||nx>=128||ny<0||ny>=128) continue; if((*info.theMap)[nx][ny].type==MAPPATTERN_OCEAN) orth_ocean=true; }
                                    if(!orth_ocean) continue;
                                    // 去重
                                    bool close=false; for(const auto &q:cands){ if(abs(q.x-p.x)+abs(q.y-p.y)<=4){ close=true; break; } }
                                    if(!close) cands.push_back(p);
                                }
                            }
                            g_ai_state.transport_landing_candidates.swap(cands);
                            g_ai_state.transport_landing_index = 0;
                            if(!g_ai_state.transport_landing_candidates.empty()){
                                ai->DebugText("Prepared " + to_string((int)g_ai_state.transport_landing_candidates.size()) + " landing candidates");
                            }
                        }
                        // 循环尝试下一个候选点
                        if(!g_ai_state.transport_landing_candidates.empty()){
                            Point p = g_ai_state.transport_landing_candidates[g_ai_state.transport_landing_index % g_ai_state.transport_landing_candidates.size()];
                            g_ai_state.transport_landing_index++;
                            ai->HumanMove(g_ai_state.transport_sn, (p.x + 0.5) * BLOCKSIDELENGTH, (p.y + 0.5) * BLOCKSIDELENGTH);
                            last_target = p; // 记录当前目标
                            target_arrival_frame = -1; // 重置到达时间
                            ai->DebugText("Transport moving to coastal candidate (" + to_string(p.x) + "," + to_string(p.y) + ") [attempt " + to_string(g_ai_state.transport_landing_index) + "]");
                            last_unload_nudge_frame = info.GameFrame;
                            // 记录尝试历史，避免来回重复
                            int h = (p.x<<8) | p.y; g_ai_state.tried_landing_hash.insert(h);
                        }
                    }
                }
            }

            // 卸载完成：释放运输编队占用标记，并自动返航我方大陆（锚定到我岸）
            if(g_ai_state.transport_dispatched && currentLoad == 0){
                g_ai_state.transport_dispatched = false;
                g_ai_state.boarding_farmers.clear();
                g_ai_state.transport_squad.clear();
                g_ai_state.transport_landing_candidates.clear();
                g_ai_state.tried_landing_hash.clear();
                // 建立敌岸据点：记录据点陆地和驻扎的5名村民；让他们后撤2~3格并原地待命
                g_ai_state.foothold_active = true;
                // 以最近一次登陆候选或敌岸坐标作为基准
                Point baseLand = (last_target.x!=-1? last_target : g_ai_state.enemy_land_pos);
                Point land = findCoastalLandNear(baseLand, info, /*prefer_enemy_land*/true);
                if(land.x == -1) land = g_ai_state.enemy_land_pos;
                g_ai_state.foothold_land = land;
                
                // 强制农民移动到离岸2-3格的安全位置，禁止他们从事其他工作
                const int d4f[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
                int assignCnt=0;
                for(const auto &fp : info.farmers){
                    if(assignCnt>=5) break;
                    int dist = abs(fp.BlockDR - land.x) + abs(fp.BlockUR - land.y);
                    if(dist<=4){
                        // 寻找离岸2-3格的安全陆地位置
                        Point safe_pos = {-1, -1};
                        for(int r=2; r<=3; ++r){
                            for(int i=0; i<8*r; ++i){
                                Point test = getSpiralPoint(land.x, land.y, i, r);
                                if(test.x>=0 && test.x<128 && test.y>=0 && test.y<128){
                                    int tile_type = (*info.theMap)[test.x][test.y].type;
                                    if((tile_type == MAPPATTERN_GRASS || tile_type == MAPPATTERN_DESERT) && 
                                       g_ai_state.grid[test.x][test.y] == 0){
                                        safe_pos = test;
                                        break;
                                    }
                                }
                            }
                            if(safe_pos.x != -1) break;
                        }
                        
                        if(safe_pos.x != -1){
                            ai->HumanMove(fp.SN, (safe_pos.x+0.5)*BLOCKSIDELENGTH, (safe_pos.y+0.5)*BLOCKSIDELENGTH);
                            g_ai_state.foothold_farmers.insert(fp.SN);
                            assignCnt++;
                            ai->DebugText("Farmer " + to_string(fp.SN) + " moved to safe position (" + to_string(safe_pos.x) + "," + to_string(safe_pos.y) + ") - forbidden from work");
                        }
                    }
                }
                
                // 舰队守备模式与驻扎点
                g_ai_state.fleet_guard_mode = true;
                for(int r=1;r<=3;++r){ bool ok=false; for(int i=0;i<8*r && !ok;++i){ Point t=getSpiralPoint(land.x,land.y,i,r); if(t.x<0||t.x>=128||t.y<0||t.y>=128) continue; if((*info.theMap)[t.x][t.y].type==MAPPATTERN_OCEAN){ g_ai_state.fleet_rally=t; ok=true; } } if(ok) break; }

                ai->DebugText("SUCCESS: Transport unloaded all farmers! Fleet now in guard mode at rally point (" + to_string(g_ai_state.fleet_rally.x) + "," + to_string(g_ai_state.fleet_rally.y) + ")");

                // 寻找我方岸边的海面锚点（以市镇中心为参考），并停靠
                const tagBuilding* tcHome = getTownCenter(info);
                if(tcHome){
                    // 在 TC 附近找一个正交邻陆的海面锚点
                    for(int r=6; r<=40; ++r){
                        bool done=false; for(int i=0;i<8*r && !done;++i){
                            Point t = getSpiralPoint(tcHome->BlockDR, tcHome->BlockUR, i, r);
                            if(t.x<0||t.x>=128||t.y<0||t.y>=128) continue;
                            if((*info.theMap)[t.x][t.y].type!=MAPPATTERN_OCEAN) continue;
                            // 要求正交邻接陆地
                            const int d4[4][2]={{0,-1},{1,0},{0,1},{-1,0}}; bool adj=false;
                            for(int d=0; d<4 && !adj; ++d){ int nx=t.x+d4[d][0], ny=t.y+d4[d][1]; if(nx<0||nx>=128||ny<0||ny>=128) continue; int tp=(*info.theMap)[nx][ny].type; if(tp==MAPPATTERN_GRASS||tp==MAPPATTERN_DESERT) adj=true; }
                            if(!adj) continue;
                            // 返航移动到半格中心
                            ai->HumanMove(g_ai_state.transport_sn, (t.x+0.5)*BLOCKSIDELENGTH, (t.y+0.5)*BLOCKSIDELENGTH);
                            g_ai_state.transport_shore_pos = t;
                            g_ai_state.transport_anchored = true;
                            done=true;
                        }
                        if(done) break;
                    }
                }
            }
        } else {
            // 运输船可能被销毁，重新寻找
            g_ai_state.transport_sn = -1;
            g_ai_state.transport_dispatched = false;
        }
    }
    // ------------------------------------------------------------------
    // 7.5. 建筑检测：优先分配农民完成未完成的建筑
    // ------------------------------------------------------------------
    assignFarmersToUnfinishedBuildings(ai, info, available_idle_farmers);

    // ------------------------------------------------------------------
    // 8. 资源分配：空闲农民采集
    // ------------------------------------------------------------------
    for (int farmer_sn : available_idle_farmers)
    {
        // 跳过正在上船的农民，防止被重新分配工作
        if (g_ai_state.boarding_farmers.count(farmer_sn) > 0) {
            continue;
        }
        
        // 跳过敌岸据点农民，禁止他们从事任何工作
        if (g_ai_state.foothold_farmers.count(farmer_sn) > 0) {
            continue;
        }

        if (g_ai_state.woodcutterSNs.size() < 18)
        { // 优先保证6个伐木工
            int tree_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_TREE, info);
            if (tree_sn != -1)
            {
                ai->HumanAction(farmer_sn, tree_sn);
            }
        }
        else if (g_ai_state.stoneMinerSNs.size() < 0)
        { // 其次保证0个采石工
            int stone_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_STONE, info);
            if (stone_sn != -1)
            {
                ai->HumanAction(farmer_sn, stone_sn);
            }
        }
        // else if(g_ai_state.hunterSNs.size() < 0)
        else
        { // 然后分配4个去打猎
            int animal_sn = findNearestResource({g_ai_state.farmers[farmer_sn].BlockDR, g_ai_state.farmers[farmer_sn].BlockUR}, RESOURCE_GAZELLE, info);
            if (animal_sn != -1)
            {
                ai->HumanAction(farmer_sn, animal_sn);
            }
        }
    }
}


// 3. 建筑放置系统 (Building Placement System)
// 游戏开始时，围绕城镇中心规划出不同的功能区域（如住宅区、军事区）
void initializeZones(AI *ai, const tagBuilding &town_center)
{
    int base_x = town_center.BlockDR;
    int base_y = town_center.BlockUR;
    // 定义住宅区和军事区的大致位置和搜索半径
    g_ai_state.residentialZone = {base_x + 6, base_y + 6, 15};
    // 将农田区设定在市镇中心东南方向，靠近住宅区，方便送粮
    g_ai_state.farmZone = {base_x + 4, base_y + 4, 12};
    g_ai_state.militaryZone = {base_x - 6, base_y - 6, 15};
    ai->DebugText("Zones Initialized.");
}

// 根据建筑类型，选择合适的区域进行位置查找
Point findPlacement(AI *ai, int buildingType, int builder_sn, const tagInfo &info)
{
    int sizeX, sizeY;
    getBuildingSize(buildingType, sizeX, sizeY);

    switch (buildingType)
    {
    case BUILDING_HOME:
        return findPlacementInZone(sizeX, sizeY, g_ai_state.residentialZone, info); // 房屋放在住宅区
    case BUILDING_FARM:
        return findPlacementInZone(sizeX, sizeY, g_ai_state.farmZone, info);        // 农田放在农田区
    case BUILDING_ARMYCAMP:
    case BUILDING_STOCK:
    case BUILDING_GRANARY:
        return findPlacementInZone(sizeX, sizeY, g_ai_state.militaryZone, info); // 军事/经济建筑放在军事区
    default:
        return findPlacementInZone(sizeX, sizeY, g_ai_state.militaryZone, info); // 其他默认也放在军事区
    }
}
// 在指定的功能区内，通过螺旋式向外搜索的方式寻找一个可用的建造位置
Point findPlacementInZone(int sizeX, int sizeY, const Zone &zone, const tagInfo &info)
{
    // 从区域中心点开始，一圈一圈向外扩展搜索范围
    for (int r = 0; r <= zone.radius; ++r)
    {
        if (r == 0)
        { // 首先检查中心点
            if (isPlacementLegalandSafe(zone.centerX, zone.centerY, sizeX, sizeY, info))
            {
                return {zone.centerX, zone.centerY};
            }
            continue;
        }
        // 遍历当前搜索半径(r)这一圈上的所有点
        for (int i = 0; i < 8 * r; ++i)
        {
            Point p = getSpiralPoint(zone.centerX, zone.centerY, i, r);
            if (isPlacementLegalandSafe(p.x, p.y, sizeX, sizeY, info))
            {
                return p; // 找到合法位置，立即返回
            }
        }
    }
    return {-1, -1}; // 搜索完整个区域都未找到合适位置
}

// 检查给定的坐标(x, y)是否可以放置一个指定大小(sizeX, sizeY)的建筑
bool isPlacementLegalandSafe(int x, int y, int sizeX, int sizeY, const tagInfo &info)
{
    int paddedX = x - 1;
    int paddedY = y - 1;
    int paddedSizeX = sizeX + 2;
    int paddedSizeY = sizeY + 2;

    // 检查是否越界
    if (paddedX < 0 || paddedY < 0 || paddedX + paddedSizeX > 128 || paddedY + paddedSizeY > 128)
    {
        return false;
    }
    const int base_height = (*info.theMap)[x][y].height;
    if (base_height == -1)
        return false; // 不能在水上或无效地块上建造

    // 检查目标区域内的所有地块
    for (int i = 0; i < paddedSizeX; ++i)
    {
        for (int j = 0; j < paddedSizeY; ++j)
        {
            int cur_x = paddedX + i;
            int cur_y = paddedY + j;
            // 检查地势是否平坦
            if ((*info.theMap)[cur_x][cur_y].height != base_height)
            {
                return false;
            }
        }
    }

    // 4. 检查建筑本身的区域内是否有障碍物 (使用全局的grid)
    for (int i = 0; i < sizeX; ++i)
    {
        for (int j = 0; j < sizeY; ++j)
        {
            int cur_x = x + i;
            int cur_y = y + j;
            if (g_ai_state.grid[cur_x][cur_y] == 1)
            { // 检查自己的障碍物缓存
                return false;
            }
        }
    }

    return true; // 所有检查通过，是合法位置
}

// 4. 辅助与工具函数 (Helpers & Utilities)
// 根据建筑类型获取其占地大小
void getBuildingSize(int buildingType, int &sizeX, int &sizeY)
{
    switch (buildingType)
    {
    case BUILDING_HOME:
    case BUILDING_ARROWTOWER:
    case BUILDING_DOCK:
        sizeX = 2;
        sizeY = 2;
        break;
    default:
        sizeX = 3;
        sizeY = 3;
        break;
    }
}

// 计算螺旋搜索路径上的点坐标。一个纯粹的数学工具函数。
Point getSpiralPoint(int center_x, int center_y, int index, int radius)
{
    if (radius == 0)
        return {center_x, center_y};
    int dx = 0, dy = 0;
    int side_len = 2 * radius;
    int perimeter_pos = index % (8 * radius);

    if (perimeter_pos < side_len)
    {
        dx = -radius + perimeter_pos;
        dy = -radius;
    }
    else if (perimeter_pos < 2 * side_len)
    {
        dx = radius;
        dy = -radius + (perimeter_pos - side_len);
    }
    else if (perimeter_pos < 3 * side_len)
    {
        dx = radius - (perimeter_pos - 2 * side_len);
        dy = radius;
    }
    else
    {
        dx = -radius;
        dy = radius - (perimeter_pos - 3 * side_len);
    }
    return {center_x + dx, center_y + dy};
}

// 生成沿海岸线的探索路径
vector<Point> generateCoastlineExplorationPath(Point start_land, const tagInfo& info) {
    vector<Point> path;
    
    // 寻找起始点附近的海洋位置
    Point start_ocean = {-1, -1};
    for(int r = 1; r <= 10; ++r) {
        for(int i = 0; i < 8*r; ++i) {
            Point test = getSpiralPoint(start_land.x, start_land.y, i, r);
            if(test.x >= 5 && test.x < 123 && test.y >= 5 && test.y < 123 &&
               (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN) {
                // 检查是否靠近陆地
                bool near_land = false;
                for(int dx = -1; dx <= 1 && !near_land; ++dx) {
                    for(int dy = -1; dy <= 1 && !near_land; ++dy) {
                        int nx = test.x + dx, ny = test.y + dy;
                        if(nx >= 0 && nx < 128 && ny >= 0 && ny < 128 &&
                           ((*info.theMap)[nx][ny].type == MAPPATTERN_GRASS ||
                            (*info.theMap)[nx][ny].type == MAPPATTERN_DESERT)) {
                            near_land = true;
                        }
                    }
                }
                if(near_land) {
                    start_ocean = test;
                    break;
                }
            }
        }
        if(start_ocean.x != -1) break;
    }
    
    if(start_ocean.x == -1) return path; // 找不到起始海洋位置
    
    // 沿海岸线生成路径点，尝试8个方向
    Point current = start_ocean;
    vector<Point> directions = {
        {12, 0}, {8, 8}, {0, 12}, {-8, 8}, 
        {-12, 0}, {-8, -8}, {0, -12}, {8, -8}
    };
    
    set<pair<int,int>> visited; // 避免重复访问同一区域
    
    for(int step = 0; step < 8 && path.size() < 6; ++step) {
        Point next_target = {
            current.x + directions[step].x,
            current.y + directions[step].y
        };
        
        // 确保在地图范围内
        next_target.x = max(5, min(122, next_target.x));
        next_target.y = max(5, min(122, next_target.y));
        
        // 避免重复访问
        if(visited.count({next_target.x/5, next_target.y/5})) continue;
        visited.insert({next_target.x/5, next_target.y/5});
        
        // 寻找目标附近的海洋位置
        Point ocean_target = {-1, -1};
        for(int r = 0; r <= 8; ++r) {
            for(int i = 0; i < max(1, 8*r); ++i) {
                Point test = (r == 0) ? next_target : getSpiralPoint(next_target.x, next_target.y, i, r);
                if(test.x >= 5 && test.x < 123 && test.y >= 5 && test.y < 123 &&
                   (*info.theMap)[test.x][test.y].type == MAPPATTERN_OCEAN) {
                    ocean_target = test;
                    break;
                }
            }
            if(ocean_target.x != -1) break;
        }
        
        if(ocean_target.x != -1) {
            path.push_back(ocean_target);
            current = ocean_target;
        }
    }
    
    return path;
}

// 渔船探索：从我方大陆（ownLand）沿海向外分层扩展，生成一串海面目标
Point findNextFishingExploreTarget(const tagInfo& info)
{
    // 每隔一段时间或首次，重新生成一批目标
    const int REFRESH_INTERVAL = 1800; // 约30秒
    if(g_ai_state.fishing_explore_targets.empty() ||
       info.GameFrame - g_ai_state.fishing_targets_last_refresh_frame > REFRESH_INTERVAL ||
       g_ai_state.fishing_explore_index >= (int)g_ai_state.fishing_explore_targets.size())
    {
        g_ai_state.fishing_explore_targets.clear();
        g_ai_state.fishing_explore_index = 0;
        g_ai_state.fishing_targets_last_refresh_frame = info.GameFrame;

        // 锚点：市镇中心优先，否则任一已完工船坞，否则地图中心
        Point anchor = {64,64};
        if(const tagBuilding* tc = getTownCenter(info)){
            anchor = {tc->BlockDR, tc->BlockUR};
        }else{
            for(const auto &bd_pair : g_ai_state.buildings){
                const tagBuilding &bd = bd_pair.second;
                if(bd.Type == BUILDING_DOCK && bd.Percent == 100){ anchor = {bd.BlockDR, bd.BlockUR}; break; }
            }
        }

        // 使用“同心圈+螺旋”的近似BFS，从近到远搜集距离己方陆地(ownLand)1-2格的海面格
        // 这样渔船会在距离海岸线1-2格的位置航行，避免严格贴岸导致的卡住问题
        auto add_candidate = [&](const Point &p){
            // 去重：避免太密集，要求新点与已选点间距>6
            for(const auto &q : g_ai_state.fishing_explore_targets){
                if(abs(q.x - p.x) + abs(q.y - p.y) <= 6) return; 
            }
            g_ai_state.fishing_explore_targets.push_back(p);
        };

        for(int r = 4; r <= 56 && (int)g_ai_state.fishing_explore_targets.size() < 60; ++r){
            int pts = 8 * r;
            for(int i=0; i<pts && (int)g_ai_state.fishing_explore_targets.size() < 60; ++i){
                Point t = getSpiralPoint(anchor.x, anchor.y, i, r);
                if(t.x < 2 || t.x >= 126 || t.y < 2 || t.y >= 126) continue;
                if((*info.theMap)[t.x][t.y].type != MAPPATTERN_OCEAN) continue;

                // 仅选取与己方陆地正交相邻的海面格，保持“贴岸探索”
                int min_coast_dist = 999;
                const int d8[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}};
                for(int d=0; d<8; ++d){
                    for(int dist=1; dist<=3; ++dist){ // 检查1-3格范围内
                        int nx = t.x + d8[d][0] * dist, ny = t.y + d8[d][1] * dist;
                        if(nx<0||nx>=128||ny<0||ny>=128) continue;
                        int typ = (*info.theMap)[nx][ny].type;
                        if((typ==MAPPATTERN_GRASS || typ==MAPPATTERN_DESERT) && g_ai_state.ownLand[nx][ny]){
                            min_coast_dist = min(min_coast_dist, dist);
                            break;
                        }
                    }
                }
                // 只选择距离岸边1-2格的位置，避免卡住
                if(min_coast_dist < 1 || min_coast_dist > 2) continue;

                add_candidate(t);
            }
        }
    }

    if(g_ai_state.fishing_explore_targets.empty()) return {-1,-1};
    Point ret = g_ai_state.fishing_explore_targets[g_ai_state.fishing_explore_index % g_ai_state.fishing_explore_targets.size()];
    g_ai_state.fishing_explore_index++;
    return ret;
}

// 新增：通用螺旋搜索，以给定中心点为起点
Point findPlacementAroundPoint(int sizeX, int sizeY, Point center, int maxRadius, const tagInfo &info)
{
    // 先尝试中心点本身
    if(isPlacementLegalandSafe(center.x, center.y, sizeX, sizeY, info)) {
        return center;
    }
    
    // 然后螺旋向外搜索
    for(int r=1; r<=maxRadius; ++r){
        int points_in_ring = 8 * r;
        for(int i=0; i < points_in_ring; ++i){
            Point p = getSpiralPoint(center.x, center.y, i, r);
            if(p.x >= 0 && p.x < 128 && p.y >= 0 && p.y < 128 && 
               isPlacementLegalandSafe(p.x, p.y, sizeX, sizeY, info)) {
                return p;
            }
        }
    }
    return {-1,-1};
}
// 在所有建筑中找到并返回城镇中心
const tagBuilding *getTownCenter(const tagInfo &info)
{
    for (const auto &building : info.buildings)
    {
        if (building.Type == BUILDING_CENTER)
        {
            return &building;
        }
    }
    return nullptr;
}

// 查找距离给定点(pos)最近的特定类型(resource_type)的资源
int findNearestResource(const Point &pos, int resource_type, const tagInfo &info)
{
    int best_sn = -1;
    double min_dist_sq = 1e9; // 使用距离的平方来比较，避免开方运算，效率更高
    for (const auto &resource : info.resources)
    {
        if (resource.Type == resource_type)
        {
            double dist_sq = pow(pos.x - resource.BlockDR, 2) + pow(pos.y - resource.BlockUR, 2);
            if (dist_sq < min_dist_sq)
            {
                min_dist_sq = dist_sq;
                best_sn = resource.SN;
            }
        }
    }
    return best_sn;
}

bool is_valid_dock_location(int x, int y, const tagInfo &info)
{
    // 1. 边界检查，确保 2x2 区域不会超出地图
    if (x < 0 || y < 0 || x + 1 >= 128 || y + 1 >= 128)
    {
        return false;
    }

    // 2. 条件 A: 检查 2x2 区域是否全部为可用的海洋
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 2; ++j)
        {
            int cur_x = x + i;
            int cur_y = y + j;
            // 必须是海洋
            if ((*info.theMap)[cur_x][cur_y].type != MAPPATTERN_OCEAN)
            {
                return false;
            }
            // 不能被占用 (例如已有船只)
            if (g_ai_state.grid[cur_x][cur_y] == 1)
            {
                return false;
            }
        }
    }

    // 3. 条件 B: 检查 2x2 区域的紧邻外圈是否存在可站立的陆地
    bool has_adjacent_land = false;
    // 仅检查与 2x2 海域正交相邻的 8 个位置（上下左右各 2 个格），不允许对角
    const int offsets[8][2] = {
        {-1, 0}, {-1, 1},   // 左侧
        { 2, 0}, { 2, 1},   // 右侧
        { 0,-1}, { 1,-1},   // 上侧
        { 0, 2}, { 1, 2}    // 下侧
    };

    for(const auto& off : offsets){
        int neighbor_x = x + off[0];
        int neighbor_y = y + off[1];
        if(neighbor_x < 0 || neighbor_x >= 128 || neighbor_y < 0 || neighbor_y >= 128) continue;

        const auto &tile = (*info.theMap)[neighbor_x][neighbor_y];
        if(tile.type == MAPPATTERN_GRASS && tile.height != -1 && g_ai_state.grid[neighbor_x][neighbor_y] == 0){
            has_adjacent_land = true;
            break;
        }
    }

    return has_adjacent_land; // 只有当两个条件都满足时，才返回 true
}

// 新增辅助函数 2：使用螺旋搜索来寻找船坞位置
Point findDockPlacement(AI *ai, const tagInfo &info)
{
    const tagBuilding *tc = getTownCenter(info);
    if (!tc)
        return {-1, -1}; // 安全检查

    ai->DebugText("Starting dock placement search...");

    // 首先尝试在渔场附近建造船坞
    vector<Point> fish_locations;
    vector<Point> existing_dock_locations;
    
    // 收集现有船坞位置
    for (const auto &building : info.buildings) {
        if (building.Type == BUILDING_DOCK) {
            existing_dock_locations.push_back({building.BlockDR, building.BlockUR});
        }
    }
    
    for (const auto &resource : info.resources) {
        if (resource.Type == RESOURCE_FISH) {
            Point fish_pos = {resource.BlockDR, resource.BlockUR};
            
            // 检查这个渔场是否已经有船坞在附近（20格内）
            bool has_nearby_dock = false;
            for (const Point &dock_pos : existing_dock_locations) {
                int dist = abs(fish_pos.x - dock_pos.x) + abs(fish_pos.y - dock_pos.y);
                if (dist <= 20) {
                    has_nearby_dock = true;
                    break;
                }
            }
            
            // 只有当附近没有船坞时才考虑这个渔场
            if (!has_nearby_dock) {
                fish_locations.push_back(fish_pos);
            }
        }
    }

    // 尝试在每个渔场附近建造船坞
    for (const Point &fish_pos : fish_locations) {
        // 在渔场周围3-15格范围内寻找合适位置
        for (int radius = 3; radius <= 15; ++radius) {
            int points_on_ring = 8 * radius;
            for (int i = 0; i < points_on_ring; ++i) {
                Point p = getSpiralPoint(fish_pos.x, fish_pos.y, i, radius);
                
                if (is_valid_dock_location(p.x, p.y, info)) {
                    ai->DebugText("Found dock location near fishing area at (" + to_string(p.x) + ", " + to_string(p.y) + ")");
                    return p;
                }
            }
        }
    }
    
    // 如果渔场附近找不到，使用城镇中心为基准搜索
    int center_x = tc->BlockDR;
    int center_y = tc->BlockUR;
    int max_radius = 60; // 定义一个足够大的搜索半径

    ai->DebugText("Searching near town center as fallback...");

    // 从中心点开始，一圈圈向外螺旋搜索
    for (int r = 1; r <= max_radius; ++r)
    { // 从半径1开始
        int points_on_ring = 8 * r;
        for (int i = 0; i < points_on_ring; ++i)
        {
            Point p = getSpiralPoint(center_x, center_y, i, r);

            // 调用验证函数
            if (is_valid_dock_location(p.x, p.y, info))
            {
                ai->DebugText("Found valid dock location at (" + to_string(p.x) + ", " + to_string(p.y) + ")");
                return p; // 找到了立即返回坐标
            }
        }
    }

    ai->DebugText("Spiral search failed. No valid dock location found.");
    return {-1, -1}; // 搜索了整个区域都没找到
}

void debug_check_tile(AI *ai, int x, int y, const tagInfo &info)
{
    string msg_prefix = "Debug Check (" + to_string(x) + "," + to_string(y) + "): ";
    ai->DebugText(" "); // 空一行，方便查看
    ai->DebugText("--- Starting Detailed Dock Check for (" + to_string(x) + "," + to_string(y) + ") ---");

    // 1. 边界检查
    if (x < 0 || y < 0 || x + 1 >= 128 || y + 1 >= 128)
    {
        ai->DebugText(msg_prefix + "FAIL - Out of map bounds.");
        return;
    }

    // 2. 检查 2x2 区域
    bool area_is_ocean = true;
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 2; ++j)
        {
            int cur_x = x + i;
            int cur_y = y + j;
            if ((*info.theMap)[cur_x][cur_y].type != MAPPATTERN_OCEAN)
            {
                ai->DebugText(msg_prefix + "FAIL - Tile (" + to_string(cur_x) + "," + to_string(cur_y) + ") is not MAPPATTERN_OCEAN.");
                area_is_ocean = false;
            }
            if (g_ai_state.grid[cur_x][cur_y] == 1)
            {
                ai->DebugText(msg_prefix + "FAIL - Tile (" + to_string(cur_x) + "," + to_string(cur_y) + ") is marked as obstacle in grid.");
                area_is_ocean = false;
            }
        }
    }
    if (!area_is_ocean)
        return;
    ai->DebugText(msg_prefix + "PASS - 2x2 area is valid ocean.");

    // 3. 检查邻居
    bool has_adjacent_land = false;
    for (int i = -1; i <= 2; ++i)
    {
        for (int j = -1; j <= 2; ++j)
        {
            if (i >= 0 && i < 2 && j >= 0 && j < 2)
                continue;
            int nx = x + i;
            int ny = y + j;
            if (nx >= 0 && nx < 128 && ny >= 0 && ny < 128)
            {
                const auto &tile = (*info.theMap)[nx][ny];
                if (tile.type == MAPPATTERN_GRASS && tile.height != -1 && g_ai_state.grid[nx][ny] == 0)
                {
                    ai->DebugText(msg_prefix + "PASS - Found valid adjacent land at (" + to_string(nx) + "," + to_string(ny) + ").");
                    has_adjacent_land = true;
                    break;
                }
            }
        }
        if (has_adjacent_land)
            break;
    }

    if (has_adjacent_land)
    {
        ai->DebugText(msg_prefix + "FINAL VERDICT: SUCCESS! This is a valid location.");
    }
    else
    {
        ai->DebugText(msg_prefix + "FINAL VERDICT: FAIL! No valid adjacent land found.");
    }
    ai->DebugText("--- End of Detailed Check ---");
}

Point findCoastalStockPlacement(AI *ai, const tagInfo &info)
{
    // 1. 寻找一个船坞作为锚点
    const tagBuilding *anchor_dock = nullptr;
    for (const auto &pair : g_ai_state.buildings)
    {
        const tagBuilding &building = pair.second;
        if (building.Type == BUILDING_DOCK)
        {
            anchor_dock = &building;
            break; // 找到第一个就够了
        }
    }

    // 2. 如果还没有船坞，则无法执行此策略，直接返回
    if (anchor_dock == nullptr)
    {
        ai->DebugText("Cannot find a dock. Skipping coastal stock placement.");
        return {-1, -1};
    }

    // 3. 以船坞位置为中心，螺旋搜索一个 3x3 的合法陆地位置
    int center_x = anchor_dock->BlockDR;
    int center_y = anchor_dock->BlockUR;
    int max_radius = 30; // 增大了搜索半径，确保能找到合适的位置

    ai->DebugText("Searching for a stock placement near the dock...");

    for (int r = 5; r <= max_radius; ++r)
    { // 稍微离海岸线远一点
        int points_on_ring = 8 * r;
        for (int i = 0; i < points_on_ring; ++i)
        {
            Point p = getSpiralPoint(center_x, center_y, i, r);

            // 仓库是 3x3 的，验证位置
            if (isPlacementLegalandSafe(p.x, p.y, 3, 3, info))
            {
                ai->DebugText("Found a valid coastal stock placement at (" + to_string(p.x) + "," + to_string(p.y) + ")");
                return p;
            }
        }
    }

    ai->DebugText("Failed to find a coastal stock placement.");
    return {-1, -1};
}

bool building_type_exists(int buildingType)
{
    // 1. 检查所有已在游戏数据中出现的建筑
    for (const auto &pair : g_ai_state.buildings)
    {
        if (pair.second.Type == buildingType)
        {
            return true; // 找到了，立即返回 true
        }
    }

    // 2. 检查已下达命令但尚未完工的建筑
    if (g_ai_state.pending_buildings.count(buildingType) > 0)
    {
        return true; // 在待办清单里找到了，也算存在
    }

    // 如果两个地方都没找到，说明真的不存在
    return false;
}

// 寻找靠海陆地：
// 从给定中心陆地块出发，寻找一个四邻包含海洋且未被占用的陆地块，优先敌岸（prefer_enemy_land=true 时要求不是己方陆地）
Point findCoastalLandNear(Point center, const tagInfo& info, bool prefer_enemy_land)
{
    // 先尝试中心与附近小半径
    for(int r=0; r<=10; ++r){
        int pts = (r==0)?1:(8*r);
        for(int i=0;i<pts;++i){
            Point p = (r==0)? center : getSpiralPoint(center.x, center.y, i, r);
            if(p.x<0||p.x>=128||p.y<0||p.y>=128) continue;
            int t = (*info.theMap)[p.x][p.y].type;
            if(!(t==MAPPATTERN_GRASS || t==MAPPATTERN_DESERT)) continue;
            // 着陆点必须未被占用，以减少“靠岸无法卸载”的概率
            if(g_ai_state.grid[p.x][p.y] == 1) continue;
            if(prefer_enemy_land && g_ai_state.ownLand[p.x][p.y]) continue; // 敌岸优先：排除己方连通陆地
            // 四邻含海洋
            bool near_ocean=false; const int d4[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
            for(int d=0; d<4; ++d){
                int nx=p.x+d4[d][0], ny=p.y+d4[d][1];
                if(nx<0||nx>=128||ny<0||ny>=128) continue;
                if((*info.theMap)[nx][ny].type==MAPPATTERN_OCEAN){ near_ocean=true; break; }
            }
            if(near_ocean) return p;
        }
    }
    return {-1,-1};
}

// 建筑物检测和修补机制：检测被下单但建造进度为0或未完成的建筑，自动分配空闲村民去继续建造
void assignFarmersToUnfinishedBuildings(AI* ai, const tagInfo& info, vector<int>& available_idle_farmers) {
    vector<int> remaining_idle_farmers;

    // 建筑任务超时检测：记录建筑的首次发现时间和上次进度更新时间
    static std::unordered_map<int, int> building_first_seen_frame; // buildingSN -> frame
    static std::unordered_map<int, int> building_last_progress_frame; // buildingSN -> frame
    static std::unordered_map<int, int> building_last_percent; // buildingSN -> percent

    for (int farmer_sn : available_idle_farmers) {
        bool assigned_to_building = false;

        // 查找未完成的建筑（进度 < 100%）
        for (const auto &building : info.buildings) {
            if (building.Percent < 100) {
                // 记录建筑首次发现时间
                if (building_first_seen_frame.find(building.SN) == building_first_seen_frame.end()) {
                    building_first_seen_frame[building.SN] = info.GameFrame;
                    building_last_progress_frame[building.SN] = info.GameFrame;
                    building_last_percent[building.SN] = building.Percent;
                }

                // 检查建筑进度是否有更新
                if (building_last_percent[building.SN] != building.Percent) {
                    building_last_progress_frame[building.SN] = info.GameFrame;
                    building_last_percent[building.SN] = building.Percent;
                }
                // 检查建筑是否超时（长时间无进展）
                int frames_since_first_seen = info.GameFrame - building_first_seen_frame[building.SN];
                int frames_since_last_progress = info.GameFrame - building_last_progress_frame[building.SN];
                bool is_timeout = (frames_since_first_seen > 1800) || // 30秒无任何进展
                                 (building.Percent == 0 && frames_since_first_seen > 600) || // 进度为0且超过10秒
                                 (frames_since_last_progress > 900); // 15秒无进度更新

                // 检查这个农民是否能到达建筑位置
                int dist = abs(g_ai_state.farmers[farmer_sn].BlockDR - building.BlockDR) +
                          abs(g_ai_state.farmers[farmer_sn].BlockUR - building.BlockUR);
                if (dist <= 25) { // 稍微增加距离范围
                    // 检查是否已经有农民在建造这个建筑
                    bool building_has_worker = false;
                    for (const auto &other_farmer_pair : g_ai_state.farmers) {
                        const tagFarmer &other_farmer = other_farmer_pair.second;
                        if (other_farmer.NowState == HUMAN_STATE_WORKING &&
                            other_farmer.WorkObjectSN == building.SN) {
                            building_has_worker = true;
                            break;
                        }
                    }

                    // 分配条件：没有其他农民在建造，或者建筑任务超时需要重新分配
                    if (!building_has_worker || is_timeout) {
                        // 冷却：同一未完工建筑在一定帧数内只分配一次，避免刷指令
                        static std::unordered_map<int,int> next_assign_frame; // buildingSN -> frame
                        static std::unordered_map<int,int> failed_attempts; // buildingSN -> 失败次数
                        int allow_frame = next_assign_frame[building.SN];
                        // 超时情况下缩短冷却时间，提高响应速度
                        int cooldown_frames = is_timeout ? 30 : 90; // 超时时1秒冷却，正常时3秒冷却
                        
                        // 对0%建筑增加指数退避，避免反复尝试非法位置
                        if(building.Percent == 0) {
                            int attempts = failed_attempts[building.SN];
                            cooldown_frames = max(cooldown_frames, 300 + attempts * 300); // 5秒起步，每次失败+5秒
                        }

                        if (info.GameFrame >= allow_frame) {
                            // 特别关注建造进度为0的建筑（被下单但没人建造）
                            if (building.Percent == 0) {
                                ai->DebugText("CRITICAL: Found building with 0% progress, assigning farmer " + to_string(farmer_sn));
                            }
                            if (is_timeout) {
                                ai->DebugText("TIMEOUT: Building " + to_string(building.Type) + " stalled for " +
                                             to_string(frames_since_last_progress) + " frames, reassigning farmer " + to_string(farmer_sn));
                            }

                            // 注意参数顺序：HumanBuild(builderSN, type, x, y)
                            ai->HumanBuild(farmer_sn, building.Type, building.BlockDR, building.BlockUR);
                            ai->DebugText("Assigned farmer " + to_string(farmer_sn) + " to continue building " +
                                         to_string(building.Type) + " at (" + to_string(building.BlockDR) + "," +
                                         to_string(building.BlockUR) + ") progress: " + to_string(building.Percent) + "%");
                            next_assign_frame[building.SN] = info.GameFrame + cooldown_frames;
                            
                            // 如果建筑进度为0%，增加失败计数
                            if(building.Percent == 0) {
                                failed_attempts[building.SN]++;
                            }
                        }
                        assigned_to_building = true;
                        break;
                    }
                }
            }
        }

        if (!assigned_to_building) {
            remaining_idle_farmers.push_back(farmer_sn);
        }
    }

    // 更新可用农民列表
    available_idle_farmers = remaining_idle_farmers;
}

/*##########YOUR CODE ENDS HERE##########*/

